はじめに
前回のFormType編に続き、Controller編をやっていきます。
Controllerとは・・・説明が難しいです。簡単にぐぐってみると「ModelとViewを制御する」みたいな説明をよく見ます。
必要なデータを取得してviewに渡したり、ユーザーが入力したデータによって振る舞いが変わったりしてると思います。
そういう難しい事は置いといて、Controller編ではEC-CUBEのカスタマイズの一例として新しく一覧ページを作成する方法を説明します。
Controllerの作成例
今回参考にする本体ソースはEC-CUBEの中でもシンプル(個人的見解)な会員処理を見てみます。
参考にする本体ソース:Eccube/Controller/Admin/Customer/CustomerController.php
参考ソースを元に必要最低限な部分を取り出してみます。
登録メールの再送やデータ削除、CSVダウンロードなどの関数もありますが、ここでは一覧を表示するindexのみ取り出します。
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の一覧処理と比べてみてください。
大きな違いは無いと思います。
このように、本体のコードを参考にすれば、ゼロからControllerを作るより簡単ですし、本体のコードを読む練習にもなると思います。
ですので、同じようなページを作りたい場合は、本体のコードをコピーしてこねくり回し、作成してみてください。
他のページは?
一覧以外に必須なのは、新規登録・編集やに削除処理は必須だと思います。
それぞれの処理も本体コピーして作成するのが良いと思いますが、商品や受注処理を参考にするのはオススメしないです。
商品や受注処理は、結構特殊な作りになっているので、参考にはならないです。
EC-CUBEでCRUDを作成する場合は、会員管理の処理を参考にするのが一番良いと思います。
Controllerのカスタマイズについて
CustomizeフォルダでControllerを作成する場合は、新規Routeを追加する場合のみ利用した方が良いです。
既存のルーティングを上書きする事もできますが、それをやってしまうとアップデートが大変になります。(アップデート時の変更が反映しないなど。)
どうしても既存ルーティングをカスタマイズしたい場合は、本体ソースを変更しgit管理するのが良いと思います。
最後に
ControllerはEC-CUBE本体を参考にして作成し、経験を積むしかないと思っています。
特に登録編集処理などが難しい部分だと思いますが、この辺はデータを送信してバリデーションする処理を理解する必要もあります。
会員の登録編集、お問合せの送信辺りの処理はフォーム処理はシンプルで、理解するのに最適な部分だと思ってます。
Controllerはある程度処理の形もありますが、発想と閃きも必要になってくると思うので、本体ソースを読んで色んな処理方法をみて、理解するのが上級者への道だと思います。