EC-CUBE4　管理画面のCRUD　脱初心者三歩目　其ノ四　Controller編

#はじめに

前回の[FormType](https://qiita.com/dev_belltzel/items/33a242b03a9b4bca149d)編に続き、Controller編をやっていきます。

Controllerとは・・・説明が難しいです。簡単にぐぐってみると「ModelとViewを制御する」みたいな説明をよく見ます。

必要なデータを取得してviewに渡したり、ユーザーが入力したデータによって振る舞いが変わったりしてると思います。

そういう難しい事は置いといて、Controller編ではEC-CUBEのカスタマイズの一例として新しく一覧ページを作成する方法を説明します。

#Controllerの作成例

今回参考にする本体ソースはEC-CUBEの中でもシンプル（個人的見解）な会員処理を見てみます。

参考にする本体ソース：[Eccube/Controller/Admin/Customer/CustomerController.php](https://github.com/EC-CUBE/ec-cube/blob/4.1/src/Eccube/Controller/Admin/Customer/CustomerController.php)

参考ソースを元に必要最低限な部分を取り出してみます。
登録メールの再送やデータ削除、CSVダウンロードなどの関数もありますが、ここでは一覧を表示する`index`のみ取り出します。

```php
namespace Eccube\Controller\Admin\Customer;

use Doctrine\ORM\QueryBuilder;
use Eccube\Controller\AbstractController;
use Eccube\Form\Type\Admin\SearchCustomerType;
use Eccube\Repository\CustomerRepository;
use Eccube\Repository\Master\PageMaxRepository;
use Eccube\Util\FormUtil;
use Knp\Component\Pager\PaginatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class CustomerController extends AbstractController
{

    /**
     * @var PageMaxRepository
     */
    protected $pageMaxRepository;

    /**
     * @var CustomerRepository
     */
    protected $customerRepository;

    public function __construct(
        PageMaxRepository $pageMaxRepository,
        CustomerRepository $customerRepository
    ) {
        $this->pageMaxRepository = $pageMaxRepository;
        $this->customerRepository = $customerRepository;
    }

    /**
     * @Route("/%eccube_admin_route%/customer", name="admin_customer", methods={"GET", "POST"})
     * @Route("/%eccube_admin_route%/customer/page/{page_no}", requirements={"page_no" = "\d+"}, name="admin_customer_page", methods={"GET", "POST"})
     * @Template("@admin/Customer/index.twig")
     */
    public function index(Request $request, $page_no = null, PaginatorInterface $paginator)
    {
        
        $session = $this->session;
        $builder = $this->formFactory->createBuilder(SearchCustomerType::class);

        $searchForm = $builder->getForm();

        $pageMaxis = $this->pageMaxRepository->findAll();
        $pageCount = $session->get('eccube.admin.customer.search.page_count', $this->eccubeConfig['eccube_default_page_count']);
        $pageCountParam = $request->get('page_count');
        if ($pageCountParam && is_numeric($pageCountParam)) {
            foreach ($pageMaxis as $pageMax) {
                if ($pageCountParam == $pageMax->getName()) {
                    $pageCount = $pageMax->getName();
                    $session->set('eccube.admin.customer.search.page_count', $pageCount);
                    break;
                }
            }
        }

        if ('POST' === $request->getMethod()) {
            $searchForm->handleRequest($request);
            if ($searchForm->isValid()) {
                $searchData = $searchForm->getData();
                $page_no = 1;

                $session->set('eccube.admin.customer.search', FormUtil::getViewData($searchForm));
                $session->set('eccube.admin.customer.search.page_no', $page_no);
            } else {
                return [
                    'searchForm' => $searchForm->createView(),
                    'pagination' => [],
                    'pageMaxis' => $pageMaxis,
                    'page_no' => $page_no,
                    'page_count' => $pageCount,
                    'has_errors' => true,
                ];
            }
        } else {
            if (null !== $page_no || $request->get('resume')) {
                if ($page_no) {
                    $session->set('eccube.admin.customer.search.page_no', (int) $page_no);
                } else {
                    $page_no = $session->get('eccube.admin.customer.search.page_no', 1);
                }
                $viewData = $session->get('eccube.admin.customer.search', []);
            } else {
                $page_no = 1;
                $viewData = FormUtil::getViewData($searchForm);
                $session->set('eccube.admin.customer.search', $viewData);
                $session->set('eccube.admin.customer.search.page_no', $page_no);
            }
            $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
        }

        $qb = $this->customerRepository->getQueryBuilderBySearchData($searchData);

        $pagination = $paginator->paginate(
            $qb,
            $page_no,
            $pageCount
        );

        return [
            'searchForm' => $searchForm->createView(),
            'pagination' => $pagination,
            'pageMaxis' => $pageMaxis,
            'page_no' => $page_no,
            'page_count' => $pageCount,
            'has_errors' => false,
        ];
    }
}
```

表示件数、検索条件、表示するページNoの処理がほとんどです。
初期アクセス、ページ送り、他画面から戻った時（編集ページなどから）といった操作に合わせてsessionからデータを取得したり記録したりしています。

このコードを基本に、session名やRepository名といった部分を変更し、Repositoryに`getQueryBuilderBySearchData`のような絞り込み処理を用意すれば、一覧ページのControllerが完成します。
（namespaceなども変更してくださいね。）

ProductやOrderの一覧処理と比べてみてください。

[Productの一覧処理](https://github.com/EC-CUBE/ec-cube/blob/b0c61a5fe5ad44589ed28a8c2eec40baa7aa1693/src/Eccube/Controller/Admin/Product/ProductController.php#L154)
[Orderの一覧処理](https://github.com/EC-CUBE/ec-cube/blob/b0c61a5fe5ad44589ed28a8c2eec40baa7aa1693/src/Eccube/Controller/Admin/Order/OrderController.php#L196)

大きな違いは無いと思います。

このように、本体のコードを参考にすれば、ゼロからControllerを作るより簡単ですし、本体のコードを読む練習にもなると思います。
ですので、同じようなページを作りたい場合は、本体のコードをコピーしてこねくり回し、作成してみてください。

#他のページは？
一覧以外に必須なのは、新規登録・編集やに削除処理は必須だと思います。
それぞれの処理も本体コピーして作成するのが良いと思いますが、商品や受注処理を参考にするのはオススメしないです。

商品や受注処理は、結構特殊な作りになっているので、参考にはならないです。

EC-CUBEでCRUDを作成する場合は、会員管理の処理を参考にするのが一番良いと思います。

#Controllerのカスタマイズについて

[ドキュメント](https://doc4.ec-cube.net/customize_controller)

CustomizeフォルダでControllerを作成する場合は、新規Routeを追加する場合のみ利用した方が良いです。

[既存のルーティングを上書き](https://doc4.ec-cube.net/customize_controller#ec-cube%E6%97%A2%E5%AD%98%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B)する事もできますが、それをやってしまうとアップデートが大変になります。（アップデート時の変更が反映しないなど。）

どうしても既存ルーティングをカスタマイズしたい場合は、本体ソースを変更しgit管理するのが良いと思います。

#最後に
ControllerはEC-CUBE本体を参考にして作成し、経験を積むしかないと思っています。

特に登録編集処理などが難しい部分だと思いますが、この辺はデータを送信してバリデーションする処理を理解する必要もあります。

会員の登録編集、お問合せの送信辺りの処理はフォーム処理はシンプルで、理解するのに最適な部分だと思ってます。

Controllerはある程度処理の形もありますが、発想と閃きも必要になってくると思うので、本体ソースを読んで色んな処理方法をみて、理解するのが上級者への道だと思います。