是否可以为每个底层RDBMS设置一个DateTime映射器?

时间:2016-12-24 10:56:44

标签: php datetime pdo 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字段。执行选择,插入,更新或删除时,应将其映射到底层可能分割的日期和时间字段。如果用户通过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]);
    }
}

正如我在

中的文档中找到的那样

Oracle

MySQL

PostgreSQL

这应该有效。在MySQL中,时区是数据库中的一个设置,所以我们无需关注。这也只是一个例子。但是,完成版本中的这些文件很快就会成为framework的一部分。由于我自己的Date类在输出时自动计算出本地日期字符串,因此我们在这里使用DateTime作为参数,以便两者都可以传入。

1 个答案:

答案 0 :(得分:1)

创建适配器接口!

<?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