How to porting a Plugin 3.0.x to 3.n ?
I. Apply new techniques
II. Structure
3.0 | 3.n/4 |
[plugin code]
├── Controller
├── Entity
│ ├── [xxx].php
│ ├── [none]
│ ├── [none]
├── Form
│ ├── Type
│ ├── Extension
├── Repository
├── Resource
│ ├── doctrine
│ ├── migration
│ ├── [none]
│ ├── locale/message.[ja,en].yml
│ ├── template
├── ServiceProvider
├── [Name]Event.php
├── config.yml
├── event.yml
├── [none]
├── [none]
├── PluginManager.php
|
[plugin code]
├── Controller
├── Entity
│ ├── [xxx].php
│ ├── [xxx]Trait.php [new]
│ ├── [xxx]Extend.php [new]
├── Form
│ ├── Type
│ ├── Extension
├── Repository
├── Resource
│ ├── [removed]
│ ├── [removed]
│ ├── config/service.yml [new]
│ ├── locale/messages.[ja,en].yml [change name]
│ ├── template
├── [removed]
├── [Name]Event.php
├── config.yml
├── [removed]
├── [xxx]QueryCustomizer.php [new]
├── Nav.php [new]
├── PluginManager.php
|
III. Controller
- Extend AbstractController, many available variables are useful for development.
- By eliminating ServiceProvider, routing in the controller is easy to monitor. Using: @Route.
- You can injection multiple services/repositories by construct function.
- Many annotation you can use in controller: @Route, @Template, …
3.0 | 3.n/4 |
public function index(Application $app, Request $request)
|
/**
* @Method("POST")
* @Route("/%eccube_admin_route%/plugin/ProductPriority/config", name="product_priority_admin_config")
* @Template("@ProductPriority/admin/config.twig")
*/
public function index(Request $request)
|
$app['eccube.plugin.xxx']
|
public function __construct(xxxRepository $xxxRepository)
{
$this->xxxRepository = $xxxRepository;
}
use: $this->configRepository
|
$app['form.factory']
|
$this->formFactory (in AbstractController)
|
$app['eccube.plugin.xxx']
|
public function __construct(xxxRepository $xxxRepository)
{
$this->xxxRepository = $xxxRepository;
}
use: $this->xxxRepository
|
$app['orm.em']
|
$this->entityManager (in AbstractController)
|
$app->addSuccess
|
$this->addSuccess
|
return $app->render(
'ProductPriority/Resource/template/admin/config.twig',
[
'form' => $form->createView(),
]
);
|
// if you use @Template, then
return [
'form' => $form->createView(),
];
---
// if you don't use it,
return $this->render(
'@ProductPriority/admin/config.twig',
[
'form' => $form->createView(),
]
);
|
$app->redirect($app->url('xxx'));
|
$this->redirectToRoute('xxx');
|
- Reference: https://github.com/EC-CUBE/sample-payment-plugin/blob/master/Controller/PaymentController.php
IV. Entity
- By removed
Resource/doctrine/xxx.yml
, Entity will handle it by annotation
(doctrine orm mapping)
- In new version, you can extend a table in core using
trait
.
- Support by inheritance mapping, you can define difference entity that uses the same table in core by
extends
.
- Entity
3.0 | 3.n/4 |
class Config extends AbstractEntity
|
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="plg_sample_payment_config")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
* @ORM\HasLifecycleCallbacks()
* @ORM\Entity(repositoryClass="Plugin\SamplePayment\Repository\ConfigRepository")
*/
class Config extends AbstractEntity
|
private $id;
|
/**
* @var int
*
* @ORM\Column(name="id", type="integer", options={"unsigned":true})
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
|
- Trait
```php
use Eccube\Annotation\EntityExtension;
use Doctrine\ORM\Mapping as ORM;
/**
- @EntityExtension(“Eccube\Entity\Customer”)
*/
trait CustomerTrait
{
/**
- カードの記憶用カラム.
*
- @var string
- @ORM\Column(type=”smallint”, nullable=true)
*/
public $sample_payment_cards;
}
```
- Extend
use Eccube\Entity\Category;
use Doctrine\ORM\Mapping as ORM;
/**
*
* @ORM\Entity(repositoryClass="Plugin\ExtendCategory\Repository\ExtendCategoryRepository")
*/
class ExtendCategory extends Category
- For form extension, you can use form theme for new attribute.
class [ProductType]Extension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description', TextType::class, [
// ...
'eccube_form_options' => [
'auto_render' => true,
'form_theme' => "@ExamplePlugin/admin/description.twig",
],
]);
}
// ...
}
VI. Repository
- Just change a little in construct function.
```php
use Eccube\Repository\AbstractRepository;
use Plugin\xxx\Entity\Config;
use Symfony\Bridge\Doctrine\RegistryInterface;
class ConfigRepository extends AbstractRepository
{
public function __construct(RegistryInterface $registry)
{
// please pass the entity to construct
parent::__construct($registry, Config::class);
}
}
## VII. Resource
- By deleting doctrine directory, they change into entities (see IV Entity).
- By deleting migration directory, you can create data in PluginManager, please see below.
- In now, you can define new services/parameter/constant in config/services.yml
- locale/`message`.[ja,en].yml change to locale/`messages`.[ja,en].yml. And you can use locale/messages.[ja,en].php
1. config/services.yml
```yml
# パラメータ定義
parameters:
sample_payment.xxx: 1
# コンテナ定義
services:
- template:
You change extend from:
3.0 | 3.n/4 |
default_frame.twig
|
@admin/default_frame.twig
|
VIII. ServiceProvider
- Removed on new version:
- Routing will move to controller’s annotation.
- Service will move to Resouce/config/services.yml
- Translator will move to Resouce/config/messages.[ja,en].yml
- Navi of admin will move to Nav.php (see below)
IX. Event
- By deleting event.yml, all hookpoint will defined in same [xxx]Event.php file.
- Remove some event: route, controller, …
- New event: query customizer (see below)
- [xxx]Event.php with implements
Symfony\Component\EventDispatcher\EventSubscriberInterface
;
- In Template event, 2 new functions added. (addAsset and addSnippet)
3.0 | 3.n/4 |
// event.yml
```yml
admin.product.edit.complete:
- [onAdminProductEditComplete, NORMAL]
Admin/Order/edit.twig:
- [onAdminOrderEditTwig, NORMAL]
```
|
// [xxx]Event.php
```php
/**
*例:
* - array('eventName' => 'methodName')
* - array('eventName' => array('methodName', $priority))
* - array('eventName' => array(array('methodName1', $priority), array('methodName2')))
*/
public static function getSubscribedEvents()
{
return [
EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE => 'onAdminProductEditComplete'
'@admin/Order/edit.twig' => 'onAdminOrderEditTwig',
];
}
```
|
[xxx]Event.php
```php
public function onProductDetailRender(TemplateEvent $event)
{
...
$twig = $this->app['twig'];
$twigAppend = $twig->getLoader()->getSource('[plugin code]/Resource/template/default/xxx.twig');
$twigSource = $event->getSource();
// Render new template by `str_replace`
$twigSource = $this->renderPosition($twigSource, $twigAppend, $this->pluginTag);
...
}
```
|
[xxx]Event.php
```php
public function onProductDetailRender(TemplateEvent $event)
{
// position will define by javascript in product_review.twig file
$event->addSnippet('@[plugin code]/default/xxx.twig');
}
```
[plugin code]/Resource/template/default/xxx.twig
```js
$(function () {
$('#new_area').appendTo($('div.ec-layoutRole__main'));
});
```
```html
...
```
|
X. config.yml
- Remove some attributes:
- Remove service provider
- Service: declare in Resource/config/services.yml (see in Resource)
- orm.path: removed migration so remove it.
- const: move to Resource/config/services.yml (see in Resource)
3.0 | 3.n/4 |
```yml
name: [Name of Plugin]
code: [Code of Plugin]
version: [Version of Plugin]
event: [Handle Class]
service:
- [Name of Plugin]ServiceProvider
orm.path:
- /Resource/doctrine
const:
Constant_ABC: XYZ
```
|
```yml
name: [Name of Plugin]
code: [Code of Plugin]
version: [Version of Plugin]
```
|
XI. QueryCustomizer
- You can change some query builder
Repository class |
QueryKey |
ProductRepository::getQueryBuilderBySearchData() |
QueryKey::PRODUCT_SEARCH |
ProductRepository::getQueryBuilderBySearchDataForAdmin() |
QueryKey::PRODUCT_SEARCH_ADMIN |
ProductRepository::getFavoriteProductQueryBuilderByCustomer |
QueryKey::PRODUCT_GET_FAVORITE |
CustomerRepository::getQueryBuilderBySearchData() |
QueryKey::CUSTOMER_SEARCH |
OrderRepository::getQueryBuilderBySearchData() |
QueryKey::ORDER_SEARCH |
OrderRepository.getQueryBuilderBySearchDataForAdmin() |
QueryKey::ORDER_SEARCH_ADMIN |
OrderRepository::getQueryBuilderByCustomer() |
QueryKey::ORDER_SEARCH_BY_CUSTOMER |
class AdminProductListCustomizer extends OrderByCustomizer
{
protected function createStatements($params, $queryKey)
{
return [new OrderByClause('p.id')];
}
public function getQueryKey()
{
return QueryKey::PRODUCT_SEARCH_ADMIN;
}
}
- Reference: http://doc3n.ec-cube.net/customize_repository
XII. Nav
- You can add to navi of admin by create
Nav.php
class SamplePaymentNav implements \Eccube\Common\EccubeNav
{
public static function getNav()
{
return [
'order' => [
'children' => [
'sample_payment_admin_payment_status' => [
'name' => 'sample_payment.admin.nav.payment_list',
'url' => 'sample_payment_admin_payment_status',
]
]
],
];
}
}
XIII. Plugin manager
- You can migration data in here.
3.0 |
3.n/4 |
public function enable($config, $app)
|
public function enable($config, ContainerInterface $container)
|
$entityManager = $app['orm.em'];
|
$entityManager = $container->get('doctrine.orm.entity_manager');
|
// repository/service
$app['eccube.plugin.xxxx'];
|
$container->get([Repository,Service]::class);
|
XIV. Reference plugin
https://github.com/EC-CUBE/sample-payment-plugin