【EC-CUBE4.3】フロントにページをプラグインから追加する手順メモ

## はじめに
- やり方が分からなかったため、備忘録として。
- 公式の無料プラグインを参考にしました。

https://github.com/EC-CUBE/ProductReview-plugin



## PluginManager.php について
- ここにインストール時、有効化時、アンインストール時、等の処理を記載する。

```php
namespace Plugin\FaqManager;

use Doctrine\ORM\EntityManagerInterface;
use Eccube\Entity\Layout;
use Eccube\Entity\Page;
use Eccube\Entity\PageLayout;
use Eccube\Common\EccubeConfig;
use Eccube\Plugin\AbstractPluginManager;
use Psr\Container\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;

class PluginManager extends AbstractPluginManager
{
    private array $pages = [
        [
            'name'     => 'FAQ',
            'url'      => 'faq_manager_index',
            'filename' => 'FaqManager/Resource/template/default/index',
        ],
    ];

    // 有効化時
    public function enable(array $meta, ContainerInterface $c)
    {
        $em = $c->get('doctrine')->getManager();

        foreach ($this->pages as $p) {
            $this->createPage($em, $p['name'], $p['url'], $p['filename']);
        }
        $this->copyTwigFiles($c);
    }

    // アンインストール時
    public function uninstall(array $meta, ContainerInterface $c)
    {
        $em = $c->get('doctrine')->getManager();
        foreach ($this->pages as $p) {
            $this->removePage($em, $p['url']);
        }
        $this->removeTwigFiles($c);
    }

    /* ---------- 以下ヘルパ --------- */

    private function createPage(EntityManagerInterface $em, string $name, string $url, string $filename): void
    {
        if ($em->getRepository(Page::class)->findOneBy(['url' => $url])) {
            return; // 重複防止
        }
        $page = (new Page())
            ->setEditType(Page::EDIT_TYPE_DEFAULT)
            ->setName($name)
            ->setUrl($url)
            ->setFileName($filename);
        $em->persist($page);
        $em->flush();

        $layout = $em->find(Layout::class, Layout::DEFAULT_LAYOUT_UNDERLAYER_PAGE);
        $em->persist(
            (new PageLayout())
                ->setPage($page)->setPageId($page->getId())
                ->setLayout($layout)->setLayoutId($layout->getId())
                ->setSortNo(0)
        );
        $em->flush();
    }

    private function removePage(EntityManagerInterface $em, string $url): void
    {
        $page = $em->getRepository(Page::class)->findOneBy(['url' => $url]);
        if (!$page) {
            return;
        }
        foreach ($page->getPageLayouts() as $pl) {
            $em->remove($pl);
        }
        $em->flush();
        $em->remove($page);
        $em->flush();
    }

    private function copyTwigFiles(ContainerInterface $c): void
    {
        $themeDir = $c->get(EccubeConfig::class)->get('eccube_theme_front_dir');
        $dst = $themeDir.'/FaqManager/Resource/template/default';
        $fs = new Filesystem();
        if (!$fs->exists($dst)) {
            $fs->mkdir($dst);
            $fs->mirror(__DIR__.'/Resource/template/default', $dst);
        }
    }

    private function removeTwigFiles(ContainerInterface $c): void
    {
        $themeDir = $c->get(EccubeConfig::class)->get('eccube_theme_front_dir');
        (new Filesystem())->remove($themeDir.'/FaqManager');
    }
}
```

---

## コントローラ、ルーティング等

```php
namespace Plugin\FaqManager\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Attribute\Route;

class FaqController extends AbstractController
{
    // @Route("/faq", name="faq_manager_index", methods={"GET", "POST"})
    // @Template("FaqManager/Resource/template/default/faq/index.twig")

    public function index()
    {
        return [];
    }
}
```
テンプレートパスを `@FaqManager/...` にしておくと、**プラグイン内テンプレート**を直接読める。  
ただし管理画面で編集したい場合は、`Page.file_name` のパスに合わせて **テーマ側コピー**を使う。

---

### ハマったところ
```php
// PluginManager.php
class PluginManager extends AbstractPluginManager
{
    private array $pages = [
        [
            'name'     => 'FAQ',
            'url'      => 'faq_manager_index', // ← ココ
            'filename' => 'FaqManager/Resource/template/default/index',
        ],
    ];

// FaqController.php
class FaqController extends AbstractController
{
                        // ↓ ココ
    // @Route("/faq", name="faq_manager_index", methods={"GET", "POST"})
    // @Template("FaqManager/Resource/template/default/faq/index.twig")
```
- 画像の箇所を統一してなかったため、うまくルーティングの設定ができていなかった。
---

### 参考リンク

https://doc4.ec-cube.net/plugin_development