【问题标题】:Hand rolling an ORM Class -- Singleton, Static Parent,?手动滚动 ORM 类——单例,静态父级,?
【发布时间】:2012-03-30 01:17:00
【问题描述】:

我正在为我公司购买的数据仓库编写网络报告扩展。数据仓库是数据模型中立的,并且具有存储表关系和字段的元层数据的表。这使我可以很容易地编写一个基本的 ORM 类,这正是我想要做的。一切正常,但是...

我的 ORM 类包含 PDO 实例、表的字段(用作白名单)和字段的元层信息。它还具有映射表关系(生成 FROM / JOIN 子句)和映射从 Web 提供的过滤器(生成 WHERE 子句)的便利功能。

SELECT 子句根据请求的模型在 ORM 的子类中生成。当页面加载时,需要构建几个模型。显然,我只需要一个 ORM 实例(如单态),但我希望每个子类都继承 ORM 的属性和便利功能——无需在每次实例化子类时重做父类的查询。

单例模式可能适合这里,但我发现很难对单例进行子类化。而且我似乎无法让静态属性正常工作。

我想我已经接近了,但我要么错过了一些东西,要么让这件事变得太难了。我现在正在考虑将属性放入一个薄类并从那里扩展,同时将便利功能与特征混合。我已经看到有关此主题的类似问题,但尚未提出明确的解决方案。

我不在工作,但这是一个简化的代码示例,应该可以为您提供我正在尝试做的事情的要点。

Class ORM {

    protected $conn;
    protected $fields;
    protected $relations;
    protected $table;
    protected $sql;

    public function __construct ($view, $database) {

        $this->conn = new PDO(...$database...);
        $this->table = $view;
        $this->getFields();
        $this->getRelations();
    }

    private function getFields () {
        //select fields from metalayer where table = $table;
        //$this->fields = $result;
    }

    private function getRelations () {
        //select relations from relations where table = $table;
        //$this->relations = $result;
    }

    protected function mapTables ($tables) {
        // $this->sql = "FROM $this->table";
        // foreach ($tables as $table) {
        //    $this->sql .= "LEFT JOIN $table ON $relations[$table]['key1'] =  $relations[$table]['key2'];
    }

    protected function mapFilters ($filters) {
        // $this->sql = "WHERE 1=1";
        // foreach $filters as $filter {
        // $this->sql .= "AND ($filter['field'] = $filter['criterion1'] OR ...criterion2, etc.)
    }
}

Class ExampleModelDAO extends ORM {
    public function __construct($view, $database, $params) {
       parent::__construct($view, $database);
       // parse params
       parent::mapTables($tables);
       parent::mapFilters($filters);
   }

   public function get() {
      // Prepend $this->sql with SELECT statement specific to model
      //  Query database and return model
   }
}

【问题讨论】:

  • 您应该将 PDO 实例作为依赖项传入。这将使您在进行测试时更容易替换为模拟对象。

标签: php oop


【解决方案1】:

首先,您的 orm/model 不应该对数据库有任何了解。有一百万种方法可以做到这一点,但我将从一个简单的数据库类开始,它在 pdo 之上提供一些额外的功能,但完全独立于其他任何东西。这也将允许您在不需要模型的情况下直接访问数据库,并允许您创建独立于数据库的模型。为了获得最大的灵活性,您需要研究适配器模式和数据映射器。但是,为了简单起见,这里有一个非常基本的示例(没有适配器或数据映射器),将模型映射到数据存储。

<?php
class DB extends PDO {
    public function __construct() {
        try {
            parent::__construct(/* db info */);
        } catch (Exception $e) {
            // handle the error
        }
    }

    public function read() {
        // read from database
    }

    public function write() {
        // write to database
    }

    // etc...
}

所以你的数据库类将有一些简单的 crud 操作。然后你的 orm 可以像这样与这个类进行交互......

<?php
class ORM {
    public function __construct() {
        $this->db = new DB();
    }

    public function find($options) {
        return $this->db->read($options);
    }

    public function save($data) {
        return $this->db->create($data); // or update()
    }

    // etc...
}

这应该足以让您继续前进。此外,如果您不在外部管理连接,您可以使用简单的修改注册表类型模式(注意这不是真正的注册表),而不是为您的数据库使用单例模式

<?php

class DB extends PDO {
    protected static $instances = array();

    public function __construct() ...

    public static function get($name) {
        if(! isset(self::$instances[$name]) {
            self::$instances[$name] = new self();
        }
        return self::$instances[$name];
    }
}

class ORM {
    public function __construct() {
        $this->db = DB::get('connection1');
    }
}

有更好的方法可以做到这一点,但我会留给你。

【讨论】:

  • 附带说明,ORM应该了解数据库——毕竟它是一个Object-relational-Mapper。它知道如何将对象模型呈现给开发人员,同时将其转换为另一端的 RDBMS 调用。 模型不需要了解数据库。
  • 感谢您的意见,但我不同意。如果您的数据层被正确抽象,那么您的 orm 可以写入数据库、会话、缓存、日志等,而对它正在写入的对象一无所知。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多