ec-cube4でプラグイン開発を始める｜ページ追加

プラグイン開発しているとほぼやることになるページ追加の手順メモ。

大まかな手順は

1. PluginManger
    2. 有効化にした際にページを追加
    3. 無効化にした際にページを削除
2. テンプレートファイルの追加
3. コントローラー追加

今回はメーカー一覧ページを追加する流れを書く。

## PluginMangerに処理を書く
まず最初にページ挿入の関数を作成

```php
/**
     * ページ情報を挿入する dtb_page, dtb_page_layout
     *
     * @param  ContainerInterface  $container
     * @param $page
     *
     * @throws ORMException
     * @throws OptimisticLockException
     */
    private function createPage(
        ContainerInterface $container,
        $addPage
    ): void {
        $pageRepository = $container->get(PageRepository::class);
        $pageFindResult = $pageRepository->findOneBy(['url' => $addPage['url']]);

        // dtb_page に存在しないことを確認する
        if ($pageFindResult !== null) {
            return;
        }

        // dtb_layout から下層ページ用レイアウトを取得する
        $layoutRepository = $container->get(LayoutRepository::class);
        $underLayout      = $layoutRepository->findOneBy(['id' => $addPage['edit_type']]);

        // dtb_page_layout の次のSortNoを取得する
        $pageLayoutRepository = $container->get(PageLayoutRepository::class);
        $LastPageLayout       = $pageLayoutRepository->findOneBy([], ['sort_no' => 'DESC']);
        $nextSortNo           = $LastPageLayout->getSortNo() + 1;

        // EntityManager準備
        $em = $container->get('doctrine.orm.entity_manager');
        $em->beginTransaction();

        // INSERT INTO dtb_page
        $page = $pageRepository->newPage();
        $page->setName($addPage['name'])
            ->setUrl($addPage['url'])
            ->setFileName($addPage['file_name'])
            ->setEditType($addPage['edit_type'])
            ->setMetaRobots($addPage['meta_robots']);
        $em->persist($page);
        $em->flush($page);

        // INSERT INTO dtb_page_layout
        $pageLayout = new PageLayout();
        $pageLayout->setLayout($underLayout)
            ->setLayoutId($underLayout->getId())
            ->setPageId($page->getId())
            ->setSortNo($nextSortNo)
            ->setPage($page);
        $em->persist($pageLayout);
        $em->flush($pageLayout);
        $em->commit();
    }
```

pages変数に追加したページの情報を記述。
ここで設定するurlは後ほど作成するControllerと合わせる必要があるので間違えないように注意。

```php
private $pages = [
        [
            'name'        => 'メーカー一覧',
            'url'         => 'maker_index',
            'file_name'   => '@Maker4/default/list',
            'meta_robots' => null,
            'edit_type'   => 2,
        ],
    ];
```

次にプラグインを有効化した際にページ追加の関数を呼び出す。
同じページが

```php
/**
     * プラグイン有効化時に走る
     *
     * @param  array  $meta
     * @param  ContainerInterface  $container
     *
     * @throws \Exception
     */
    public function enable(array $meta, ContainerInterface $container)
    {
        foreach ($this->pages as $addPage) {
            //既存ページがないかを確認
            $isPage = $container->get(PageRepository::class)->findOneBy(['url' => $addPage['url']]);
            if (null === $isPage) {
                $this->createPage($container, $addPage);
            }
        }
    }
```
最後に削除する関数を追加して準備おｋ。

```php
/**
     * ページ情報を削除 dtb_page, dtb_page_layout
     *
     * @param  ContainerInterface  $container
     *
     * @throws ORMException
     * @throws OptimisticLockException
     */
    private function deletePage(ContainerInterface $container, $addPage): void
    {
        // dtb_page に存在することを確認する
        $pageRepository = $container->get(PageRepository::class);
        $page           = $pageRepository->findOneBy(['url' => $addPage['url']]);
        if ($page === null) {
            return;
        }

        // EntityManager準備
        $em = $container->get('doctrine.orm.entity_manager');
        $em->beginTransaction();

        // DELETE FROM dtb_page WHERE インストール時にINSERTしたページ
        $em->remove($page);
        $em->flush($page);

        // DELETE FROM dtb_page_layout WHERE インストール時にINSERTしたページレイアウト
        $pageLayoutRepository = $container->get(PageLayoutRepository::class);
        $pageLayout           = $pageLayoutRepository->findOneBy(['page_id' => $page->getId()]);
        if ($pageLayout !== null) {
            $em->remove($pageLayout);
            $em->flush($pageLayout);
        }
        $em->commit();
    }
```

全体はこんな感じ。

```PluginManger.php
<?php

declare(strict_types=1);
namespace Plugin\Maker4;

use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Eccube\Entity\PageLayout;
use Eccube\Plugin\AbstractPluginManager;
use Eccube\Repository\LayoutRepository;
use Eccube\Repository\PageLayoutRepository;
use Eccube\Repository\PageRepository;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class PluginManager.
 */
class PluginManager extends AbstractPluginManager
{
    private $pages = [
        [
            'name'        => 'メーカー一覧',
            'url'         => 'maker_index',
            'file_name'   => '@Maker4/default/list',
            'meta_robots' => null,
            'edit_type'   => 2,
        ],
    ];

    /**
     * プラグイン有効化時に走る
     *
     * @param  array  $meta
     * @param  ContainerInterface  $container
     *
     * @throws \Exception
     */
    public function enable(array $meta, ContainerInterface $container)
    {
        foreach ($this->pages as $addPage) {
            //既存ページがないかを確認
            $isPage = $container->get(PageRepository::class)->findOneBy(['url' => $addPage['url']]);
            if (null === $isPage) {
                $this->createPage($container, $addPage);
            }
        }
    }


    /**
     * プラグイン無効化時・アンインストール時に走る
     *
     * @param  array  $meta
     * @param  ContainerInterface  $container
     *
     * @throws ORMException
     * @throws OptimisticLockException
     * @throws \Exception
     */
    public function disable(
        array $meta,
        ContainerInterface $container
    ) {
        foreach ($this->pages as $addPage) {
            $this->deletePage($container, $addPage);
        }
    }

    /**
     * ページ情報を挿入する dtb_page, dtb_page_layout
     *
     * @param  ContainerInterface  $container
     * @param $page
     *
     * @throws ORMException
     * @throws OptimisticLockException
     */
    private function createPage(
        ContainerInterface $container,
        $addPage
    ): void {
        $pageRepository = $container->get(PageRepository::class);
        $pageFindResult = $pageRepository->findOneBy(['url' => $addPage['url']]);

        // dtb_page に存在しないことを確認する
        if ($pageFindResult !== null) {
            return;
        }

        // dtb_layout から下層ページ用レイアウトを取得する
        $layoutRepository = $container->get(LayoutRepository::class);
        $underLayout      = $layoutRepository->findOneBy(['id' => $addPage['edit_type']]);

        // dtb_page_layout の次のSortNoを取得する
        $pageLayoutRepository = $container->get(PageLayoutRepository::class);
        $LastPageLayout       = $pageLayoutRepository->findOneBy([], ['sort_no' => 'DESC']);
        $nextSortNo           = $LastPageLayout->getSortNo() + 1;

        // EntityManager準備
        $em = $container->get('doctrine.orm.entity_manager');
        $em->beginTransaction();

        // INSERT INTO dtb_page
        $page = $pageRepository->newPage();
        $page->setName($addPage['name'])
            ->setUrl($addPage['url'])
            ->setFileName($addPage['file_name'])
            ->setEditType($addPage['edit_type'])
            ->setMetaRobots($addPage['meta_robots']);
        $em->persist($page);
        $em->flush($page);

        // INSERT INTO dtb_page_layout
        $pageLayout = new PageLayout();
        $pageLayout->setLayout($underLayout)
            ->setLayoutId($underLayout->getId())
            ->setPageId($page->getId())
            ->setSortNo($nextSortNo)
            ->setPage($page);
        $em->persist($pageLayout);
        $em->flush($pageLayout);
        $em->commit();
    }

    /**
     * ページ情報を削除 dtb_page, dtb_page_layout
     *
     * @param  ContainerInterface  $container
     *
     * @throws ORMException
     * @throws OptimisticLockException
     */
    private function deletePage(ContainerInterface $container, $addPage): void
    {
        // dtb_page に存在することを確認する
        $pageRepository = $container->get(PageRepository::class);
        $page           = $pageRepository->findOneBy(['url' => $addPage['url']]);
        if ($page === null) {
            return;
        }

        // EntityManager準備
        $em = $container->get('doctrine.orm.entity_manager');
        $em->beginTransaction();

        // DELETE FROM dtb_page WHERE インストール時にINSERTしたページ
        $em->remove($page);
        $em->flush($page);

        // DELETE FROM dtb_page_layout WHERE インストール時にINSERTしたページレイアウト
        $pageLayoutRepository = $container->get(PageLayoutRepository::class);
        $pageLayout           = $pageLayoutRepository->findOneBy(['page_id' => $page->getId()]);
        if ($pageLayout !== null) {
            $em->remove($pageLayout);
            $em->flush($pageLayout);
        }
        $em->commit();
    }
}
```

## テンプレートファイルの追加
Plugin名/Resource/template/default/list.twigを追加。

## Controller
Plugin名/Controller/MakerController.phpに以下ファイルを作成

```makerContrller.php
declare(strict_types=1);
namespace Plugin\Maker4\Controller;

use Eccube\Controller\AbstractController;
use Plugin\Maker4\Repository\MakerRepository;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

/**
 * Class MakerController.
 */
class MakerController extends AbstractController
{
    /**
     * @var MakerRepository
     */
    protected $makerRepository;

    /**
     * MakerController constructor.
     *
     * @param  MakerRepository  $makerRepository
     */
    public function __construct(MakerRepository $makerRepository)
    {
        $this->makerRepository = $makerRepository;
    }

    /**
     * メーカー一覧
     * @Route("/maker", name="maker_index")
     * @Template("@Maker4/default/list.twig")
     */
    public function list(): array
    {
        $makers = $this->makerRepository->findAll();

        return ['makers'=> $makers];
    }
}
```

管理画面のページ管理に作成したページにアクセス出来れば終わり！！

Call to a member function getPath() on nullって怒られる場合は、ControllerのNameとPluginMangerで設定したURLで差異がある可能性が高い。

自分がそうだったんでｗ