【EC-CUBE 4】デフォルトのRepositoryを拡張する方法

この記事では、既存のリポジトリを拡張して新しい機能を追加する方法について紹介します。

【動作環境】
EC CUBEのバージョン:4.2.2
サーバー:Xserver

開発前にデバッグモードの設定をお薦めします

デバッグモードを設定しておくと、エラーが起きたときに詳細情報が表示されるようになります。
エラー箇所を探しやすくなるので、開発前に設定しておくのをオススメします。
デバッグモードの設定方法については 以下記事 で解説しています。

カスタマイズ後は、デバッグモードの解除を忘れないように。

目次

ProductRepositoryを拡張する

ProductRepositoryに新しい関数を定義したい場面を考えます。
例として、以下のような【特定のタグをもつ商品のみを表示する一覧ページ】を作成してみます。

【サンプル】というタグが付いた商品のみを表示するページ

こちらのページは 【EC-CUBE 4】特定のタグを付けた商品のみを抽出し、一覧ページを作る方法 にて既に紹介済ですが、商品の検索機能(クエリ)をControllerに定義しています。(リポジトリについては触れていません。)

ただ再利用性やメンテナンス性の観点から、このようなデータベースに関するクエリはリポジトリに移行することが推奨されています。

そこで今回は、以下のような手順で前回記事の内容を改善したいと思います。

  • ProductRepositoryの機能を引き継いだCustomProductRepositoryという新しいリポジトリを作成する。
  • 前回記事で紹介しているControllerファイルのクエリ部分を、CustomProductRepositoryに移行する。
  • Controllerで、CustomProductRepositoryに移行したクエリを呼び出す。
STEP

CustomProductRepositoryの作成

以下コードを記したファイルを作成し、「app/Customize/Repository」にアップします。

<?php

namespace Customize\Repository;

use Eccube\Repository\ProductRepository;

class CustomProductRepository extends ProductRepository
{
    public function findProductsByTagId($tagId)
    {
        $qb = $this->createQueryBuilder('p');
        $qb->innerJoin('p.ProductTag', 'pt')
            ->innerJoin('pt.Tag', 't')
            ->andWhere('t.id = :Tag')
            ->setParameter('Tag', $tagId);

        return $qb->getQuery()->getResult();
    }
}

クラスを定義する際にextends ProductRepositoryを付け加えることで、既存のProductRepositoryの機能を引き継いだRepositoryとして利用できます。

今回はこちらのクラスに、新しいメソッドfindProductsByTagId($tagId)を定義し、Controller側で定義していたクエリを移行しました。

あとは、Controller側でこのメソッドを呼び出せばいいですね。

STEP

Controllerで移行したクエリを利用

続いて、以下コードを記したControllerファイルを「Customize/Controller」下にアップします。

<?php

namespace Customize\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Eccube\Controller\AbstractController;
use Customize\Repository\CustomProductRepository;

class SampleProductPageController extends AbstractController
{
   /**
     * @var CustomProductRepository
     */
    protected $customProductRepository;

    /**
     * @param CustomProductRepository $customProductRepository
     */
     public function __construct(CustomProductRepository $customProductRepository) {
        $this->customProductRepository = $customProductRepository;
    }
    
    /**
     * @Route("/lists/sample", name="lists_sample")
     * @Template("lists_sample.twig")
     */
    public function index(Request $request)
    { 
        $TagProducts = $this->customProductRepository->findProductsByTagId(4);

        return [
            'TagProducts' => $TagProducts,
        ];

    }
}

前回はuseステートメントでProductRepositoryを利用していましたが、今回はSTEP 1で作成したCustomProductRepositoryを利用します。

また、indexメソッドに定義していたクエリはリポジトリに移行したので削除し、$TagProducts =$this->customProductRepository->findProductsByTagId(4);としてCustomProductRepositoryに定義したメソッドを呼び出します。

メソッドの引数には、抽出したいタグのIDを設定します。

リポジトリの移行はこれで完了です。
あとは、前回記事こちらの記事 を参考に、Twigテンプレートも用意してページを作ってみてください!

メソッドをリポジトリに移行するメリットのまとめ

再利用性

同じクエリを、他のコントローラやサービスでも使用できるようになる。

今回の例では、メソッドを呼び出す際に引数のIDを変えるだけで、任意のタグが付いた商品をピックアップして表示できるようにもなっています。

テストの容易性

リポジトリのメソッドを、単体でテストしやすくなる。

コードの整理

コントローラは、HTTPリクエストとレスポンスのハンドリングがメイン、リポジトリはデータの取得や保存がメインとなり、各ファイルの責務が明確になる。

メンテナンス性

仮にデータベースのスキーマやクエリのロジックが変更された場合、リポジトリの中だけで変更を行うことができ、他の部分のコードは変更不要となる。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次