我在我的项目中使用带有 PHP 的工作单元设计模式

Posted

技术标签:

【中文标题】我在我的项目中使用带有 PHP 的工作单元设计模式【英文标题】:I'm using Unit Of Work Design Pattern with PHP for my project 【发布时间】:2014-01-18 12:02:37 【问题描述】:

我正在开发一个使用工作单元设计模式的项目。它包括 Storage,EntityCollection,..... 工作单元代码包括 PDO Adapter 代码文件。但是适配器对于运行查询来说并不完整。我从某个地方找到了这些文件。 我无法构建我想要的查询。每次我编写代码时,我都会遇到许多与查询相关的问题。所以你能帮我让它更灵活吗...例如我想像这样运行: $db->select()->where('id>:id')->andWhere('')->orWHere ()->orderBy()->groupBy()->have()->fetch()/fetchOne();或类似的。

<?php

namespace D\Adapter;

class PdoAdapter implements \D\DB\DatabaseInterface 

    protected $config = array();
    protected $database;
    protected $connection;
    protected $statement;
    protected $fetchMode = \PDO::FETCH_ASSOC;

    public function __construct($dsn, $username = null, $password = null, array $driverOptions = array()) 
        $this->config = compact("dsn", "username", "password", "driverOptions");
        $this->database = $driverOptions['db_name'];
    

    public function getStatement() 
        if ($this->statement === null) 
            throw new \PDOException(
            "There is no PDOStatement object for use.");
        
        return $this->statement;
    

    public function connect() 
        // if there is a PDO object already, return early
        if ($this->connection) 
            return;
        

        try 
            $this->connection = new \PDO(
                    $this->config["dsn"], $this->config["username"], $this->config["password"], $this->config["driverOptions"]);
            $this->connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
            $this->connection->setAttribute(
                    \PDO::ATTR_EMULATE_PREPARES, false);
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    public function disconnect() 
        $this->connection = null;
    

    public function prepare($sql, array $options = array()) 
        $this->connect();

        try 
            $this->statement = $this->connection->prepare($sql, $options);

            return $this;
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    public function execute(array $parameters = array()) 

        try 
            $this->getStatement()->execute($parameters);
            return $this;
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    public function countAffectedRows() 
        try 
            return $this->getStatement()->rowCount();
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    /**
     * countAffectedRows iin Alias
     */
    public function count() 
        try 
            return $this->getStatement()->rowCount();
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    public function getLastInsertId($name = null) 
        $this->connect();
        return $this->connection->lastInsertId($name);
    

    public function fetch($fetchStyle = null, $cursorOrientation = null, $cursorOffset = null) 
        if ($fetchStyle === null) 
            $fetchStyle = $this->fetchMode;
        

        try 
            return $this->getStatement()->fetch($fetchStyle, $cursorOrientation, $cursorOffset);
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    public function fetchAll($fetchStyle = null, $column = 0) 
        if ($fetchStyle === null) 
            $fetchStyle = $this->fetchMode;
        

        try 
            return $fetchStyle === \PDO::FETCH_COLUMN ? $this->getStatement()->fetchAll($fetchStyle, $column) : $this->getStatement()->fetchAll($fetchStyle);
         catch (\PDOException $e) 
            throw new \RunTimeException($e->getMessage());
        
    

    public function select($table, $bind = array(), $where = "", $options = array()) 
        if (count($bind) > 0) 
            foreach ($bind as $col => $value) 
                unset($bind[$col]);
                $bind[":" . $col] = $value;
            
        
        if (isset($options['fields'])) 
            $fields = $options['fields'];
         else 
            $fields = '*';
        
        $sql = "SELECT " . $fields . " FROM " . $table . " ";

        if (strlen($where) > 2) 
            $sql .= "WHERE " . $where;
        

//        set_flash($sql);
        $this->prepare($sql)
                ->execute($bind);

        return $this;
    

    public function query($sql, array $bind = array()) 
        if (is_array($bind)) 
            foreach ($bind as $col => $value) 
                unset($bind[$col]);
                $bind[":" . $col] = $value;
            
        

        $this->prepare($sql)
                ->execute($bind);
        return $this;
    

    public function insert($table, array $bind) 
        $cols = implode(", ", array_keys($bind));
        $values = implode(", :", array_keys($bind));
        foreach ($bind as $col => $value) 
            unset($bind[$col]);
            $bind[":" . $col] = $value;
        

        $sql = "INSERT INTO " . $table
                . " (" . $cols . ")  VALUES (:" . $values . ")";
        return (int) $this->prepare($sql)
                        ->execute($bind)
                        ->getLastInsertId();
    

    public function update($table, array $bind, $where = "") 
        $set = array();
        foreach ($bind as $col => $value) 
            unset($bind[$col]);
            $bind[":" . $col] = $value;
            $set[] = $col . " = :" . $col;
        

        $sql = "UPDATE " . $table . " SET " . implode(", ", $set)
                . (($where) ? " WHERE " . $where : " ");
        return $this->prepare($sql)
                        ->execute($bind)
                        ->countAffectedRows();
    

    public function delete($table, $where = "") 
        $sql = "DELETE FROM " . $table . (($where) ? " WHERE " . $where : " ");
        return $this->prepare($sql)
                        ->execute()
                        ->countAffectedRows();
    

    public function fetchAllTables() 
        $sql = "SHOW TABLES FROM " . $this->database;
        $this->prepare($sql)
                ->execute();

        return $this;
    

    public function fetchAllFields($table) 
        $sql = "SHOW FIELDS FROM " . $table;
        $this->prepare($sql)
                ->execute();

        return $this;
    


---完整代码在这里--- https://github.com/batmunkhcom/mbm/tree/master/src/D

【问题讨论】:

【参考方案1】:

首先,UnitOfWork 模式的关注点是跟踪您在业务事务中所做的所有可能影响数据库的事情。事务完成后,它会根据您的工作计算出更改数据库所需的所有操作。你的班级还有其他顾虑。

它看起来像一个神级(反模式)。它有不止一项职责:Connection、PeparedStatement、Execution 和其他助手。它很难扩展和维护。尝试将所有职责以SOLID 的方式与相应的设计模式拆分到不同的类。

您在代码中面临的想法已经由其他框架完成。再次实施它非常艰苦。例如你可以试试Doctrine ORM/DBAL Framework。

【讨论】:

github.com/batmunkhcom/mbm/tree/master/src/D 这是我的完整包裹清单。工作单元来自互联网的某个地方。我不想使用 Doctrine 或其他框架。如果 pdo 适配器很好并且集成良好,我可以轻松编写其他适配器。我找到了phpclasses.org/package/… 不错的 pdo 适配器。但是很难集成到工作单元中...... ***.com/questions/267629/…

以上是关于我在我的项目中使用带有 PHP 的工作单元设计模式的主要内容,如果未能解决你的问题,请参考以下文章

使用无脂肪框架进行单元测试

我在我的 CSS 文件中添加了一行文本,垃圾来自浏览器

带有php的引导网格[重复]

带有 Catch 库的未解析外部符号

带有可可豆荚的 GHUnit

在 spark 中创建带有模式的配置单元外部表