どーも!marusukeです!
前回の記事の続きで(【Laminas】リポジトリクラスのfindAllPostsメソッドを実装する!)、LaminasDbSqlRepositoryクラスのリファクタリングとfindPostメソッドの実装をしていきます!
LaminasDbSqlRepositoryクラスのリファクタリングをする!
今の時点で、LaminasDbSqlRepositoryのリファクタリングをします。(コードの変更量が少ないうちに。)
リファクタリングとは、簡単に説明すると、今あるコードをエンジニアが読みやすく書き換えるということです。(処理内容は変わりません。)
今回のリファクタリングは、クラスの依存性が高い部分(直接インスタンス化させている部分)をコンストラクタのプロパティに変更し、クラスの依存性を低くします。
簡単にいうと、インスタンスの引数で、new クラス名()となっている部分です。
クラスの依存性が高い部分は以下の 部分です。
public function findAllPosts()
{
$sql = new Sql($this->db);
$select = $sql->select('posts');
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
if (! $result instanceof ResultInterface || ! $result->isQueryResult()) {
return [];
}
$resultSet = new HydratingResultSet(
new ReflectionHydrator(),
new Post('', '')
);
$resultSet->initialize($result);
return $resultSet;
}
依存度が高いとは、簡単に説明をすると、未来の仕様変更で上記のReflectionHydrator()やPost(”, ”)が別のオブジェクトを使用するとなった時、この部分のコードも書き換える必要があります。(use文もです。)大規模なシステムの場合だと、この変更部分を探すことが大変です。
したがって、Factoryデザインパターンで、インスタンス化はFactoryクラスにお願いして、Factoryクラスから引数でReflectionHydrator()とやPost()をもらう形にします。(Factoryクラスは次の記事で作成します。)
(FactoryデザインパターンはGoFデザインパターンの一つで、簡単に説明すると、クラスをインスタンス化する工場のことです。)
以下が依存性を低くしたLaminasDbSqlRepository.phpです。
// In module/Blog/src/Model/LaminasDbSqlRepository.php:
namespace Blog\Model;
use InvalidArgumentException;
use RuntimeException;
// Replace the import of the Reflection hydrator with this:
use Laminas\Hydrator\HydratorInterface;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Db\Adapter\Driver\ResultInterface;
use Laminas\Db\ResultSet\HydratingResultSet;
use Laminas\Db\Sql\Sql;
class LaminasDbSqlRepository implements PostRepositoryInterface
{
/**
* @var AdapterInterface
*/
private $db;
/**
* @var HydratorInterface
*/
private $hydrator;
/**
* @var Post
*/
private $postPrototype;
public function __construct(
AdapterInterface $db,
HydratorInterface $hydrator,
Post $postPrototype
) {
$this->db = $db;
$this->hydrator = $hydrator;
$this->postPrototype = $postPrototype;
}
/**
* Return a set of all blog posts that we can iterate over.
*
* Each entry should be a Post instance.
*
* @return Post[]
*/
public function findAllPosts()
{
$sql = new Sql($this->db);
$select = $sql->select('posts');
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
if (! $result instanceof ResultInterface || ! $result->isQueryResult()) {
return [];
}
$resultSet = new HydratingResultSet($this->hydrator, $this->postPrototype);
$resultSet->initialize($result);
return $resultSet;
}
/**
* Return a single blog post.
*
* @param int $id Identifier of the post to return.
* @return Post
*/
public function findPost($id)
{
}
}
簡単に説明すると、コンストラクターに型付きプロパティ$hydratorと$postPrototypeを追加しました。
次の記事で作成するFactoryクラスで、インスタンスを作成し、$hydratorと$postPrototypeに代入します。
($postPrototypeは、Postエンティティの原型という意味です。プロトタイプについて詳しくはこちら)
これでリファクタリングは完了しました!
findPostメソッドを実装する!
最後にLaminasDbSqlRepositoryクラスの2つ目のメソッドである、findPostメソッドを完成させましょう!
以下、findPostメソッドの内容です。
public function findPost($id)
{
$sql = new Sql($this->db);
$select = $sql->select('posts');
$select->where(['id = ?' => $id]);
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
if (! $result instanceof ResultInterface || ! $result->isQueryResult()) {
throw new RuntimeException(sprintf(
'Failed retrieving blog post with identifier "%s"; unknown database error.',
$id
));
}
$resultSet = new HydratingResultSet($this->hydrator, $this->postPrototype);
$resultSet->initialize($result);
$post = $resultSet->current();
if (! $post) {
throw new InvalidArgumentException(sprintf(
'Blog post with identifier "%s" not found.',
$id
));
}
return $post;
}
1つ目のメソッドである、findAllPostsメソッドとの差は、 の部分です。
ほぼfindAllPostsメソッドの内容を同じです。
findAllPostsメソッドと異なる部分のみ上から簡単に説明しますと、
findPostメソッドの引数として、$idを取得します。
$select->where([‘id = ?’ => $id]);で引数で取得したidを元にwhere句に代入し、その後executeしデータベースから該当するデータを取得します。
$post = $resultSet->current();のcurrent()は、取得した行データのみを取り出すメソッドです。
if (! $post) {…}は、$postに取得した行データが入っているか確認します。なければエラーを返します。
$post;は、取り出した行データを返します。
これで、findPostメソッドの実装が完了しました!お疲れ様でした!
次は、LaminasDbSqlRepositoryFactoryクラスを作成します!
コメント