エンジニ屋.com(エンジニヤドットコム)

日々得たWebエンジニアに関する情報をアウトプットしてます!

【symfony】 Repositoryとは 使用具体例で紹介【Eccube4】


本記事は、symfonyで利用されるRepositoryファイルについて使用具体例に沿って紹介していきます。

symfonyを触りはじめたけどRepositoryの必要性や使い方など、なかなか掴みづらいなーと感じている方などが対象となります。

私も最初の頃参考書の定義を読んでも全然ピンと来ませんでした。。。

そもそもリポジトリといえばGitで保管場所として使われているので、保管場所に使用するのかなと思っていましたが、関係ありませんでした!

これから紹介する具体例に沿って理解を深めて頂ければ幸いです。


まずは参考書に書かれている定義を載せておきます。

Repositoryとは

対応するエンティティと関連付けられたテーブルから、必要に応じてレコードをエンティティとして取り出すための各種機能を提供するユーティリティクラスといってよいでしょう。エンティティを取得るためのさまざまな機能を提供しています。
出典 : PHPフレームワーク Symfony 4入門


う〜んなんとなく分かるような、分からないような。
私も最初は全然理解が出来ませんでした。

簡単に説明すると、データベースにあるデータから必要なデータのみを取得したり、並び替えたりしてControllerに渡す役目を受けている場所です。

百聞は一見に如かずなので、具体例を紹介していきます。

Repositoryの作成


Eccubeのデフォルトで存在するデータベースのテーブルを使用したほうが分かりやすいと思うので、商品情報が入っているEntityのProductを使用して紹介していきます。

因みにDB上には下記データが既に入っている状態です。

Productデータ

先ずは、app\Customize\Repository\CustomizeProductRepository.phpを作成してください。

下記の通りソースコードを記述します。

<?php

namespace Customize\Repository;

use Eccube\Entity\Product; #ProductのDBから取得する為
use Symfony\Bridge\Doctrine\RegistryInterface; #Entityと連携する為
use Eccube\Repository\AbstractRepository; #Repositoryを拡張する為

/**
 * CustomizeProductRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class CustomizeProductRepository extends AbstractRepository
{
    /**
     * CustomizeProductRepository constructor.
     *
     * @param RegistryInterface $registry
     */
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Product::class); #EntityのProductを呼び出している
    }
    /**
     * 全検索
     *
     * @return Products|array
     */
    public function customFindAll() #関数名(何でも良い)
    {
        $qb = $this->createQueryBuilder('p'); #何でも良いがproductの頭文字を取ってます。

        $products = $qb
            ->getQuery() #作成したクエリを取得
            ->getResult(); #実行

        return $products;
    }
}


customFindAll()というオリジナルの関数を作りました。
31行目までのコードは、DBから値を取得する為と、class内で使用するcreateQueryBuilderメソッドを呼び出す為のclassなどを記述しています。

customFindAll内では、productのDBのクエリを生成する為のcreateQueryBuilderを先ず宣言をします。
そして、その下で$qbの変数からgetQueryでそのクエリを取得して、getResultで実行したコードを$products変数に格納して、$productsを返しています。
関数の中では、何も加工の処理を入れていないので、productのDBが全てそのまま返されます。

Controllerで取得

それでは実際にControllerから呼び出して、twigで確認していきたいと思います。

本記事では出力内容を確認したいだけなので、test用のcontollerとtwigを作成します。

app\Customize\Controller\TestController.php

<?php

namespace Customize\Controller;

use Eccube\Controller\AbstractController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Routing\Annotation\Route;
use Customize\Repository\CustomizeProductRepository; #Repositoryを取得する為の宣言

class TestController extends AbstractController
{

    /**
     * @var ProductRepository
     */
    protected $customizeProductRepository;

    /**
     *
     *
     * TestController constructor.
     *
     *  @param CustomizeProductRepository $productRepository
     *
     */

    public function __construct(CustomizeProductRepository $customizeProductRepository)
    {
      $this->customizeProductRepository = $customizeProductRepository;
    }

    /**
     *
     * @Route("/test", name="test") #URLを指定
     * @Template("test.twig") #ページ遷移先を指定
     *
     */
    public function index()
    {
        $products = $this->customizeProductRepository->customFindAll();

        return ['products'=>$products];
    }
}

不要なコードを入れると分かりにくいので、必要最小限のコードのみ入れています。

Controllerのファイル内で先ほど作成したRepositoryを呼び出して、testというURLでtest.twigに$productsを渡しています。

twigファイルで表示

これをtest.twigで表示させます。
app\template\default\test.twigを作成して下記コードのみを記載します。

そしてtestにアクセスしてください。

{% for product in products %}
<p>{{ product }}</p>
{% endfor %}

そうすると下記のように、全商品名のみが並んで表示されます。

twig表示

twigファイルをproductの横にidとつけてみましょう。

{% for product in products %}
<p>{{ product.id }}</p>
{% endfor %}

こうすることで、全id番号のみ表示することができます。

Repositoryファイル内に別メソッドで検証

実は、これだけだとRepository にオリジナルのメソッドを作成する必要はなく元から用意されているfindAllメソッドで、データを取得することができます。

なので次に、データをRepository内で少し加工して、取得したデータを表示させてみたいと思います。
先ほど貼り付けたDBの画像を見るとproduct_status_idとあります。 1が公開で、2が非公開、3が廃止のステータスの状態が番号としてProductのDBに入っています。
ではこれを非公開と廃止のステータスの状態の商品のみ表示したいと思います。

それでは、Repository のファイルに戻ります。

下記のようにコードを追加してください。

/**
     * 非公開・廃止ステータス
     *
     * @return Products|array
     */
    public function findNoPublished() #関数名(何でも良い)
    {
        $qb = $this->createQueryBuilder('p') #引数名は何でもよいです。DB名として扱われます
            ->where('p.Status > :status_id') #prodcutDBのカラムproduct_status_idのstatus_idより大きいレコードを検索
            ->setParameter('status_id', 1);#パラメータstatus_idに1を設定します。

        $products = $qb
            ->getQuery() #作成したクエリを取得
            ->getResult(); #実行

        return $products;
    }

公開以外なので、適当に関数名をfindNoPublishedとして作成しました。

大事なのは、先ほどと異なる箇所で、createQueryBuilderのあとにwhere()でStatusを指定、パラメータを設定しているところです。

これにより、1以外のステータスのデータの絞込みを実現しています。

Controllerで取得

それでは、contorollerに戻り下記のように一部追加します。

/**
     *
     * @Route("/test", name="test") #URLを指定
     * @Template("test.twig") #ページ遷移先を指定
     *
     */
    public function index()
    {
        $products = $this->customizeProductRepository->customFindAll();

        $noPublishedProducts = $this->customizeProductRepository->findNoPublished();

        return ['products'=>$products,'noPublishedProducts' => $noPublishedProducts ];
    }

そして、twigにも下記のように変更します。

{% for product in noPublishedProducts %}
<p>{{ product }}</p>
{% endfor %}

するとどうでしょう。 画像のようにステータスid1以外のみ表示ができました。
Productデータ

解説は以上となります。お疲れ様でした。

非常にシンプルなデータを扱ったので実践的ではないですが、クエリ部分を変更すれば応用はできると思います。

最後に

Eccubeはsymfonyのフレームワークで構成されています。もし「自力でもっとカスタマイズしたい」や「仕事でEccubeで開発することになった」方には、下記のsymofony4 入門の参考書をおすすめします。
こちらの参考書にはEccubeのカスタマイズ方法については一切記載されていないので、また別で学習する必要はありますが、Entity、Controller、twig、Repositoryの利用方法が非常に分かりやすく書かれています。筆者も仕事でEccubeに携わることとなり、参考書を購入し理解が深まりました。 symfonyはLaravelと密接している部分もありLaravelの構成部分の理解も深まり有益でした。
価格帯は若干高めですが、中身はしっかりしているので、購入して損はないと思います。

Have a nice development day!!!