【Laminas】blogのモデル(リポジトリ)を作る!

Laminas

どーも!marusukeです!

前回の記事では、blogの記事を追加するためのコントローラーとファクトリーとそのルートを作成しました!今回は、そのコントローラーで使用するリポジトリ(LaminasDbSqlCommandクラス)を作成します!

作成の流れとしては、

  • Formクラスを作成する。
  • コントローラーを作る。
  • コントローラーのインスタンス化のためのFactoryとルートを作る。
  • モデル(repositoryクラス)を作成する。<= 現在ここです!
  • view側を作る。

早速作っていきましょう!

モデル(LaminasDbSqlCommandクラス)で実現したいこと

このクラスの目的は、以下のデータベースに対して以下の操作をすることです。

  • 【insertPostメソッド】データベースにPostデータを挿入する。その後データベース挿入後に付与されたidと保存されたPostデータをreturnする。
  • 【updatePostメソッド】データベース内のPostデータをidで検索し、idと一致するPostデータを更新する。その後データベース更新後にidと保存されたPostデータをreturnする。
  • 【deletePostメソッド】データベース内のPostデータをidで検索し、idと一致するPostデータを削除する。

LaminasDbSqlCommandクラスを作る

前回の記事の中で、WriteControllerに、PostCommandInterfaceの型のオブジェクトを注入する実装をしています。

そのPostCommandInterfaceを継承する「LaminasDbSqlCommandクラス」を作成していきます!

以下がLaminasDbSqlCommandクラスです。

module/Blog/src/Model/LaminasDbSqlCommand.php

<?php
//①
namespace Blog\Model;

use RuntimeException;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Db\Adapter\Driver\ResultInterface;
use Laminas\Db\Sql\Delete;
use Laminas\Db\Sql\Insert;
use Laminas\Db\Sql\Sql;
use Laminas\Db\Sql\Update;

//②
class LaminasDbSqlCommand implements PostCommandInterface
{
    
    //
    private $db;

    public function __construct(AdapterInterface $db)
    {
        $this->db = $db;
    }

    //
    public function insertPost(Post $post)
    {
        $insert = new Insert('posts');
        $insert->values([
            'title' => $post->getTitle(),
            'text' => $post->getText(),
        ]);

        $sql = new Sql($this->db);
        $statement = $sql->prepareStatementForSqlObject($insert);
        $result = $statement->execute();

        if (! $result instanceof ResultInterface) {
            throw new RuntimeException(
                'Database error occurred during blog post insert operation'
            );
        }

        $id = $result->getGeneratedValue();

        return new Post(
            $post->getTitle(),
            $post->getText(),
            $id
        );
    }

    /**
     * {@inheritDoc}
     */
    public function updatePost(Post $post)
    {
    }

    /**
     * {@inheritDoc}
     */
    public function deletePost(Post $post)
    {
    }
}

上から簡単に説明していきます。

//①「namespace Blog\Model; …」部分について

namespace Blog\Model;

use RuntimeException;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Db\Adapter\Driver\ResultInterface;
use Laminas\Db\Sql\Delete;
use Laminas\Db\Sql\Insert;
use Laminas\Db\Sql\Sql;
use Laminas\Db\Sql\Update;

namespaceで、Blogディレクトリ内のModelディレクトリ内にこのPostCommand.phpがあることを指定しています。

namespaceについての詳細はこちらです。PHPマニュアル 名前空間の概要

use文で、このクラスで使用するクラスを呼び出しています。簡単に説明すると以下の用途でそれぞれのクラスを使用します。

use RuntimeException; 
=>例外処理用
use Laminas\Db\Adapter\AdapterInterface; 
=>プロパティがDB接続設定情報を含むオブジェクトであるかの確認用インターフェイス
use Laminas\Db\Adapter\Driver\ResultInterface;
=>あるオブジェクトがResultInterface型であるか確認用
use Laminas\Db\Sql\Delete;
=>DBからデータを削除するクラス
use Laminas\Db\Sql\Insert;
=>DBからデータを挿入するクラス
use Laminas\Db\Sql\Sql;
=>CRUD操作ができるメソッドを持つクラス
use Laminas\Db\Sql\Update;
=>DBからデータを削除・挿入・するクラス

上記のuse文で扱うクラスは、公式ドキュメントComponents laminas-dbに詳細が載っています。

//②「class LaminasDbSqlCommand implements PostCommandInterface{…}」について

class LaminasDbSqlCommand implements PostCommandInterface
{
...
}

このクラスは、PostCommandInterfaceから継承されています。(その理由は、WriteControllerのコンストラクタで使用するときにPostCommandInterfaceの型かどうかを確認するためです。関係する記事はこちらです。)

PostCommandInterfaceというインタフェースからの継承なので、全てのメソッドを定義する必要があります。以下の3つのメソッドが必要になります。

  • insertPostメソッド
  • updatePostメソッド
  • deletePostメソッド

それぞれのメソッドに共通するのは、プロパティにPostオブジェクト型のデータを使用します。理由は、view側の入力フォームから入力されたPostデータを、このリポジトリがデータベースに対してデータの入力や更新、削除をします。

ちなみにblog記事のデータとは、postデータ(blog記事のタイトルとblog記事の内容)のことです。

postエンティティクラス作成に関する記事はこちらです。

//③コンストラクタ部分について

private $db;

public function __construct(AdapterInterface $db)
{
    $this->db = $db;
}

コンストラクターで、AdapterInterface型のオブジェクトをこのクラス内で扱えるようにします。AdapterInterface型のオブジェクトとは、データベース接続設定情報が含まれるオブジェクトで、この後説明する、insertPostメソッドなどで使用します。

//④insertPostメソッド部分について

//①
public function insertPost(Post $post)
{
     //②
     $insert = new Insert('posts');
     $insert->values([
         'title' => $post->getTitle(),
         'text' => $post->getText(),
     ]);

     //③
     $sql = new Sql($this->db);
     $statement = $sql->prepareStatementForSqlObject($insert);
     $result = $statement->execute();

     //④
     if (! $result instanceof ResultInterface) {
         throw new RuntimeException(
             'Database error occurred during blog post insert operation'
         );
     }

     //⑤
     $id = $result->getGeneratedValue();

     return new Post(
         $post->getTitle(),
         $post->getText(),
         $id
     );
}

上から簡単に説明していきます!

//①insertPostメソッドの引数について

public function insertPost(Post $post)
{
...
}

引数は、Postオブジェクト型のみを扱うように指定しています。この引数での型チェックによってデータベースに保存されるデータがPostデータでないものを除外することが出来ます。(その他の理由としては、データを扱う際の運用上必要だからです。)

//②InsertインスタンスにPostデータを入力する部分について

$insert = new Insert('posts');
$insert->values([
     'title' => $post->getTitle(),
     'text' => $post->getText(),
]);

この部分を上から順に説明します。

  1. Insertインスタンスを変数$insertに格納します
  2. 変数$postに格納されたPostオブジェクト内のPostデータ(titleとtext)を取得し、titleキーにtitleデータ、textキーにtextデータを紐づける形で、Insertインスタンスのvaluesメソッドに引数として、配列に入力します。(Insertインスタンス内に格納されただけで、まだデータベースには保存されていません。)

ちなみにinsertクラスが持つメソッドは、こちらに詳細があります。

Components laminas-db : Insert

//③「データベースへの接続とデータを保存する」部分について

$sql = new Sql($this->db);
$statement = $sql->prepareStatementForSqlObject($insert);
$result = $statement->execute();

上から順に説明すると、

  1. Sqlクラスをインスタンス化させ、引数としてデータベース接続情報オブジェクトを渡します。そして、変数$sqlに格納します
  2. SqlインスタンスのprepareStatementForSqlObjectメソッドにpostデータが入力されたinsertインスタンスを入力します。ここまでの内容に変数$statementに格納します
  3. Sqlインスタンスのexecuteメソッドで、データベースにPostデータの保存を実行します。

このSqlクラスに関する詳細は、こちらの公式ドキュメントにあります。

Components laminas-db : SQL Abstraction

//④Sqlの実行結果の確認部分について

if (! $result instanceof ResultInterface) {
    throw new RuntimeException(
        'Database error occurred during blog post insert operation'
    );
}

この部分を簡単に説明すると、$resultは、ResultInterfaceの型を持っていなければ、’Database error occurred during blog post insert operation’(ブログ投稿の挿入操作中にデータベース エラーが発生しました)というエラーメッセージを表示するという実装になっています。

//⑤戻り値部分について

$id = $result->getGeneratedValue();

return new Post(
     $post->getTitle(),
     $post->getText(),
     $id
);

上から順に説明すると、

  1. $result(データベースからのResultオブジェクト)からgetGeneratedValueメソッドで、Postデータをデータベースに保存した時に付与されたidを取得し、$idに格納します
  2. 戻り値として、Postオブジェクトにtitle、text、idを入力し、Posオブジェクトを生成します

ここまでで、LaminasDbSqlCommandクラスが完成しました!

LaminasDbSqlCommandFactoryクラスを作成する

上記で作成したLaminasDbSqlCommandクラスをインスタンス化させるためのファクトリを作成します。

以下がLaminasDbSqlCommandFactoryクラスです!

<?php

//①
namespace Blog\Factory;

//②
use Interop\Container\ContainerInterface;
use Blog\Model\LaminasDbSqlCommand;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;

//③
class LaminasDbSqlCommandFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        return new LaminasDbSqlCommand($container->get(AdapterInterface::class));
    }
}

上から順番に説明していきます!

//①名前空間の設定部分について

namespace Blog\Factory;

名前空間をblogディレクトリ内のFactoryディレクトリ内を指定しています。この名前空間内では、LaminasDbSqlCommandクラスは一つしか存在できなくなります。

//②use文部分について

use Interop\Container\ContainerInterface;
use Blog\Model\LaminasDbSqlCommand;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;

このFactoryで必要なインターフェースやクラスを読み込んでいます。

//③クラスの定義部分について

class LaminasDbSqlCommandFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        return new LaminasDbSqlCommand($container->get(AdapterInterface::class));
    }
}

上から順に簡単に説明していきます。

  • classを「LaminasDbSqlCommandFactory」と定義しています。継承はFactoryInterfaceです。
  • __invokeメソッド(マジックメソッド)で、このクラスが読み込まれた時にこの__invokeメソッドをが実行され、メソッド内の処理が実行されます。つまりLaminasDbSqlCommandインスタンスが生成されます。

ここまででLaminasDbSqlCommandFactoryクラスが完成しました!

次にこのクラスをServiceManagerに設定します。

作成したLaminasDbSqlCommandクラスをServiceManagerに設定する

module/Blog/config/module.config.phpファイルのservice_manager内のaliase設定部分とfactory設定部分に追記します。

module/Blog/config/module.config.php

<?php

namespace Blog;

use Laminas\Router\Http\Literal;
use Laminas\ServiceManager\Factory\InvokableFactory;

return [

    'controllers' => [...],

    'view_manager' => [...],

    'service_manager' => [
        'aliases' => [
     // 既存のエイリアスは割愛します
     // 以下の部分を追加します
     Model\PostCommandInterface::class => Model\LaminasDbSqlCommand::class,
        ],
        'factories' => [
        // 既存のファクトリーは割愛します
        // 以下の部分を追加します
        Model\LaminasDbSqlCommand::class => Factory\LaminasDbSqlCommandFactory::class,
        ],
    ],

    
    'router' => [...]
       
];

上から簡単に解説します。

aliasesの追記内容について

'aliases' => [
     // 既存の設定部分は割愛します
     // 以下の部分を追加します
     Model\PostCommandInterface::class => Model\LaminasDbSqlCommand::class,
        ],

このaliases設定は、

PostCommandInterfaceがサービスマネージャで呼び出された時に、LaminasDbSqlCommandインスタンスが代わりに呼び出されるという意味になっています。

詳細は、こちらにあります。Components laminas-servicemanager : aliases

factoriesの追記内容について

'factories' => [
        // 既存のファクトリーは割愛します
        // 以下の部分を追加します
        Model\LaminasDbSqlCommand::class => Factory\LaminasDbSqlCommandFactory::class,
        ],

factories設定は、

「LaminasDbSqlCommandクラスをインスタンス化するときに使用するファクトリーはLaminasDbSqlCommandFactory」ということを意味しています。

factoriesに関する詳細はこちらです。Components laminas-servicemanager : factories

これで、LaminasDbSqlCommandFactoryリポジトリクラスをServiceManagerに設定することが出来ました!

お疲れ様でした!

次は、view側を作成していきます!

コメント

タイトルとURLをコピーしました