在我的项目中,我想构建对多个数据库引擎的支持。我通过放置在模型层中的datamappers来实现这一点。这方面的一个简单的例子看起来像(抱歉的代码墙,如果你想获得的要点跳到结尾):如何防止在为不同的数据库引擎实现数据加载器时出现重复?
用户
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');
正如你可以看到我有基本与重复代码的两个映射器(该查询是两个引擎相同)。这有点“强奸”DRY的原则,但我只是没有看到一个好的/干净/正确的方法来防止这种情况。请注意,这当然只是一个简单的例子,通常会有不同的数据库引擎中的查询。
我曾经想过让映射器延长一些映射与基本的查询,但是这种感觉更脏,因为根本不可能对某事物的基本查询。
我昨天也在PHP聊天中提出这个问题,结论基本上是“假设重复并继续你的生活”,我越想越多,我认为这是我唯一的真正选择。
但可以肯定我不是缺少一些干净和智能解决方案,我想我会在这里发表的问题。
不知道你的代码重复的意思,因为实在是没有太多的代码在那里回事。你能详细说明一下吗?此外,映射器类可以将持久层与其他层分开。或者那不是你的意思? – PeeHaa
据我所知,这两个数据库映射器的每一行是重复的 - 这很可能是不可收拾的相当快。如果你决定改变你建立连接的方式 - 你将需要修改每个映射器文件。我已经更新了答案,以便更清楚。 –