どーも!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(),
]);
この部分を上から順に説明します。
- Insertインスタンスを変数$insertに格納します
- 変数$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();
上から順に説明すると、
- Sqlクラスをインスタンス化させ、引数としてデータベース接続情報オブジェクトを渡します。そして、変数$sqlに格納します
- SqlインスタンスのprepareStatementForSqlObjectメソッドにpostデータが入力されたinsertインスタンスを入力します。ここまでの内容に変数$statementに格納します
- 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
);
上から順に説明すると、
- $result(データベースからのResultオブジェクト)からgetGeneratedValueメソッドで、Postデータをデータベースに保存した時に付与されたidを取得し、$idに格納します
- 戻り値として、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側を作成していきます!
コメント