私のプロジェクトでは、複数のデータベースエンジンのサポートを組み込みたいと思っています。これは、モデルレイヤーに配置されたデータマッパーを介して実現しています。この簡単な例は次のようになります(コードの壁については申し訳ありませんが、要点を知りたい場合は最後までスキップしてください)。
ユーザー
namespace Application\Model;
use Application\Model\Mapper;
class User
{
private $mapper;
private $id;
public function __construct(Mapper $mapper, $id)
{
$this->mapper = $mapper;
}
public function setPassword($password)
{
$this->mapper->updatePassword($this->id, $password);
}
}
マッパーインターフェース
namespace Application\Model;
interface UserMapper
{
public function updatePassword($id, $password);
}
MySQLマッパー
namespace Application\Model;
use Application\Model\Mapper;
class UserMysqlMapper implements Mapper
{
private $connection;
public function __construct(\PDO $connection)
{
$this->connection = $connection;
}
public function updatePassword($id, $password)
{
$stmt = $this->connection->prepare('UPDATE user SET password = :password WHERE userid = :userid');
$stmt->execute(['password' => $password, 'userid' => $id]);
}
}
PostgreSQLマッパー
namespace Application\Model;
use Application\Model\Mapper;
class UserPgsqlMapper implements Mapper
{
private $connection;
public function __construct(\PDO $connection)
{
$this->connection = $connection;
}
public function updatePassword($id, $password)
{
$stmt = $this->connection->prepare('UPDATE user SET password = :password WHERE userid = :userid');
$stmt->execute(['password' => $password, 'userid' => $id]);
}
}
ものをロードする
$connection = new \PDO(dsn stuff);
$mapper = \Application\Model\UserPgsqlMapper($connection);
$user = \Application\Model\User($mapper, 1);
$user->setPassword('new password');
ご覧のとおり、基本的に重複コードを持つ2つのマッパーがあります(クエリは両方のエンジンで同じです)。これはDRYの原則をいくらか「レイプ」しますが、これを防ぐための良い/クリーン/正しい方法がわかりません。もちろん、これは単なる例であり、通常、異なるデータベースエンジン間で同じではないクエリが存在することに注意してください。
マッパーにベースクエリを使用してマッパーを拡張させることを考えましたが、何かのベースクエリが存在しないため、これはさらに汚い感じがします。
昨日のPHPチャットでもこれを聞いたところ、結論は基本的に「複製を偽ってあなたの人生を続ける」でした。考えれば考えるほど、それが唯一の本当の選択肢だと思います。
しかし、クリーンでスマートなソリューションを見逃していないことを確認するために、ここに質問を投稿すると思いました。