是否可以为每个底层 RDBMS 提供一个 DateTime 映射器?
Is it possible to have a DateTime mapper for every underlaying RDBMS?
我正在尝试在 PDO
之上开发我自己的 ORM 框架,它遵循 Active Record 概念并且易于使用。深入研究后,我发现每个关系数据库对日期和时间数据类型都有自己的理解。我只想在我的 ORM 中使用 PHP 的 DateTime
并将其映射到底层 RDBMS,以便我们可以利用这些数据类型的优势。但是我不确定,如果可能的话,就想到一个时期之间的比较等等。实际上,这也是 Doctrine 的 DBAL 似乎不关心的地方。他们只是在日期和时间的不同数据类型上说not supported
。
我想要的是这样的:
MySQL: PHP DateTime => maps to MySQL DateTime field
PostgreSQL: PHP DateTime => maps to a splitted date field and a time field
Oracle: PHP DateTime => maps to TIMESTAMP
...
用户应该能够在该关系对象上使用 setter 方法设置他的 DateTime 字段。当执行select、insert、update 或delete 时,它应该映射到底层可能拆分的日期和时间字段。如果用户通过 getter 方法请求该值,则应该出现同样的情况。
请告诉我这是怎么可能的,并请提供一些例子。非常感谢! :-)
编辑:我试了一下下面提到的适配器解决方案。我认为这可以解决问题:
<?php
namespace Diana\Core\Persistence\Sql\Dbal\Gateway;
interface IAdapter
{
/**
* Drills an DateTime instance down to underlaying RDBMS date and time string.
*
* @param \DateTime $date
* @return string
*/
public function drillDownDateTime(\DateTime $date);
/**
* Parse the RDBMS rows back to an DateTime instance.
*
* @param array $rows
* @return \DateTime
*/
public function parseDateTime(array $rows);
}
<?php
namespace Diana\Core\Persistence\Sql\Dbal\Gateway;
class OracleAdapter implements IAdapter
{
const FORMAT = 'Y-m-d H:i:s e';
/**
* @inheritdoc
*/
public function drillDownDateTime(\DateTime $date)
{
return $date->format(self::FORMAT);
}
/**
* @inheritdoc
*/
public function parseDateTime(array $rows)
{
return \DateTime::createFromFormat(self::FORMAT, $rows[0]);
}
}
<?php
namespace Diana\Core\Persistence\Sql\Dbal\Gateway;
class PostgreSqlAdapter implements IAdapter
{
const FORMAT = 'Y-m-d H:i:s e';
/**
* @inheritdoc
*/
public function drillDownDateTime(\DateTime $date)
{
return $date->format(self::FORMAT);
}
/**
* @inheritdoc
*/
public function parseDateTime(array $rows)
{
return \DateTime::createFromFormat(self::FORMAT, $rows[0]);
}
}
正如我在
中的文档中所见
这应该有效。在 MySQL 中,时区是数据库中的一个设置,因此我们无需关心。这也只是一个例子。但是完成版本中的这些文件很快就会成为我的一部分 framework。由于我自己的Dateclass,在输出的时候会自动计算出本地日期字符串,所以我们这里使用DateTime
作为参数,这样两个都可以传入。
创建适配器接口!
<?php
interface DbAdapterInterface
{
/**
* @param DateTime $date
* @return string
*/
public function convertFromDateTime(DateTime $date);
/**
* @param DateTime $date
* @return array
*/
public function convertToDateTime(array $row);
}
class MySqlAdapter implements DbAdapterInterface
{
public function convertFromDateTime(DateTime $date)
{
return $date->format('Y-m-d H:i:s');
}
public function convertToDateTime(array $row)
{
return new DateTime($row['date']);
}
}
class OracleAdapter implements DbAdapterInterface
{
public function convertFromDateTime(DateTime $date)
{
return $date->getTimestamp();
}
public function convertToDateTime(array $row)
{
return new DateTime('@'.$row['date']);
}
}
class Db
{
/** @var DbAdapterInterface $adapter */
private $adapter;
public function setAdapter(DbAdapterInterface $adapter)
{
$this->adapter = $adapter;
}
public function insert($data)
{
$date = $data['date'];
$dateString = $this->adapter->convertFromDateTime($date);
// do your insert
return $dateString;
}
public function findById($id)
{
// fetch row by id here, this is just an example, I'm using the id as the date string
$row = ['date' => $id];
$row = $this->adapter->convertToDateTime($row);
// do your insert
return $row;
}
}
// Example
$data = [
'date' => new DateTime(),
];
$db = new Db();
$db->setAdapter(new MySqlAdapter());
echo $db->insert($data)."\n";
$db->setAdapter(new OracleAdapter());
echo $db->insert($data)."\n";
$time = '1493308146';
var_dump( $db->findById($time));
$db->setAdapter(new MySqlAdapter());
$time = '2014-09-18 22:00:00';
var_dump( $db->findById($time));
请在此处查看工作示例:https://3v4l.org/pYgbE
我正在尝试在 PDO
之上开发我自己的 ORM 框架,它遵循 Active Record 概念并且易于使用。深入研究后,我发现每个关系数据库对日期和时间数据类型都有自己的理解。我只想在我的 ORM 中使用 PHP 的 DateTime
并将其映射到底层 RDBMS,以便我们可以利用这些数据类型的优势。但是我不确定,如果可能的话,就想到一个时期之间的比较等等。实际上,这也是 Doctrine 的 DBAL 似乎不关心的地方。他们只是在日期和时间的不同数据类型上说not supported
。
我想要的是这样的:
MySQL: PHP DateTime => maps to MySQL DateTime field
PostgreSQL: PHP DateTime => maps to a splitted date field and a time field
Oracle: PHP DateTime => maps to TIMESTAMP
...
用户应该能够在该关系对象上使用 setter 方法设置他的 DateTime 字段。当执行select、insert、update 或delete 时,它应该映射到底层可能拆分的日期和时间字段。如果用户通过 getter 方法请求该值,则应该出现同样的情况。
请告诉我这是怎么可能的,并请提供一些例子。非常感谢! :-)
编辑:我试了一下下面提到的适配器解决方案。我认为这可以解决问题:
<?php
namespace Diana\Core\Persistence\Sql\Dbal\Gateway;
interface IAdapter
{
/**
* Drills an DateTime instance down to underlaying RDBMS date and time string.
*
* @param \DateTime $date
* @return string
*/
public function drillDownDateTime(\DateTime $date);
/**
* Parse the RDBMS rows back to an DateTime instance.
*
* @param array $rows
* @return \DateTime
*/
public function parseDateTime(array $rows);
}
<?php
namespace Diana\Core\Persistence\Sql\Dbal\Gateway;
class OracleAdapter implements IAdapter
{
const FORMAT = 'Y-m-d H:i:s e';
/**
* @inheritdoc
*/
public function drillDownDateTime(\DateTime $date)
{
return $date->format(self::FORMAT);
}
/**
* @inheritdoc
*/
public function parseDateTime(array $rows)
{
return \DateTime::createFromFormat(self::FORMAT, $rows[0]);
}
}
<?php
namespace Diana\Core\Persistence\Sql\Dbal\Gateway;
class PostgreSqlAdapter implements IAdapter
{
const FORMAT = 'Y-m-d H:i:s e';
/**
* @inheritdoc
*/
public function drillDownDateTime(\DateTime $date)
{
return $date->format(self::FORMAT);
}
/**
* @inheritdoc
*/
public function parseDateTime(array $rows)
{
return \DateTime::createFromFormat(self::FORMAT, $rows[0]);
}
}
正如我在
中的文档中所见这应该有效。在 MySQL 中,时区是数据库中的一个设置,因此我们无需关心。这也只是一个例子。但是完成版本中的这些文件很快就会成为我的一部分 framework。由于我自己的Dateclass,在输出的时候会自动计算出本地日期字符串,所以我们这里使用DateTime
作为参数,这样两个都可以传入。
创建适配器接口!
<?php
interface DbAdapterInterface
{
/**
* @param DateTime $date
* @return string
*/
public function convertFromDateTime(DateTime $date);
/**
* @param DateTime $date
* @return array
*/
public function convertToDateTime(array $row);
}
class MySqlAdapter implements DbAdapterInterface
{
public function convertFromDateTime(DateTime $date)
{
return $date->format('Y-m-d H:i:s');
}
public function convertToDateTime(array $row)
{
return new DateTime($row['date']);
}
}
class OracleAdapter implements DbAdapterInterface
{
public function convertFromDateTime(DateTime $date)
{
return $date->getTimestamp();
}
public function convertToDateTime(array $row)
{
return new DateTime('@'.$row['date']);
}
}
class Db
{
/** @var DbAdapterInterface $adapter */
private $adapter;
public function setAdapter(DbAdapterInterface $adapter)
{
$this->adapter = $adapter;
}
public function insert($data)
{
$date = $data['date'];
$dateString = $this->adapter->convertFromDateTime($date);
// do your insert
return $dateString;
}
public function findById($id)
{
// fetch row by id here, this is just an example, I'm using the id as the date string
$row = ['date' => $id];
$row = $this->adapter->convertToDateTime($row);
// do your insert
return $row;
}
}
// Example
$data = [
'date' => new DateTime(),
];
$db = new Db();
$db->setAdapter(new MySqlAdapter());
echo $db->insert($data)."\n";
$db->setAdapter(new OracleAdapter());
echo $db->insert($data)."\n";
$time = '1493308146';
var_dump( $db->findById($time));
$db->setAdapter(new MySqlAdapter());
$time = '2014-09-18 22:00:00';
var_dump( $db->findById($time));
请在此处查看工作示例:https://3v4l.org/pYgbE