【问题标题】:how to pass data mapper between models in php如何在php中的模型之间传递数据映射器
【发布时间】:2014-05-19 18:14:33
【问题描述】:

在过去的几天里,我阅读了很多关于域对象、数据映射器以及其他一些我不知道的东西。 我决定尝试在我正在编写的一些代码中实现这一点(部分是出于学习目的,部分是因为我想创建一个真正简化的框架来快速构建一些项目......使用我可以轻松理解和修改)。

在阅读了thisthis 之后,我计划创建一个单一的数据映射器,其中连接到数据库,然后使用工厂将数据映射器传递到每个域对象(嗯,那些需要它的人)。我在下面包含了一些示例代码

class data_mapper {
    private $dbh;

    function __construct() 
    {
        $this->dbh = new PDO(DB_STRING, DB_USER, DB_PASS);
    }
    public function createUser($data) ...
    public function updateUser($user_id, $data) ...
    public function createCategory($data) ...
}

class user {
    private $data_mapper;
    public $user_id;
    public $data;

    function __construct($dm) 
    {
        $this->data_mapper = $dm;
    }

    function someFunction() {
        /* some code */
        $this->data_mapper->updateUser($user_id, $data);
        /* some more code */
    }
}

class factory {    
    private $data_mapper = null;

    function __construct($dm) 
    {
        $this->data_mapper = $dm;
    }

    public function create($name)
    {
        return new $name($this->data_mapper);
    }
}
/* USAGE */
$dm = new data_mapper();
$factory = new factory($dm);
$user = $factory->create('user');

我还有两个问题:

  1. 我查看的许多最近的示例为每个模型创建了不同的 data_mapper。我应该这样做吗?如果我这样做,那不会使工厂变得更加复杂(即我需要创建单个 PDO 对象并将其传递给每个数据映射器,然后将正确的数据映射器传递给每个模型)?

  2. 如果我上面的代码暴露了对模型、数据映射器或其他任何东西的理解上的一些缺陷,请赐教(我知道这不是一个真正的问题)...

【问题讨论】:

    标签: php oop datamapper


    【解决方案1】:

    据我所知,“数据映射器”模式在现代框架中以原型模型类的形式实现,所有应用程序模型都继承自该模型类。

    在这个原型模型中,您可以实现 CRUD 方法,因此您的模型将拥有它。

    说到传递pdo,当地学者会告诉你,你应该传递PDO对象作为构造函数参数。但是,如果您看一下任何现代框架 - 他们正在使用某种包含 PDO 实例的单例

    【讨论】:

    • 如果我理解正确,您是说我应该使用 CRUD 方法创建一个 Model 类……但是,每个模型的 CRUD 方法需要不同,不是吗? ?那么 SQL 会出现在每个模型中吗?以及如何在模型之间传递 PDO 对象?
    • 为什么会这样? create() 将只获取数据数组。 update() 将只采用带有数据和标识符的数组。 read() 和 delete() 只是标识符。
    • 嗯,现代框架,如 Symfony2Zend2 出于某种原因通过 Service Manager 作为实例传递 $pdo..
    • @YourCommonSense,我并不是说我不喜欢这种方法......但是当涉及到基本 CRUD 模型时,如果 READ 方法对于某些数据很复杂(即跨越多个表等)。我认为,为了可读性,在数据映射器中使用一组特定的函数来收集数据会更容易......
    • @Irfanjamal 这就是特定模型的用途。您始终可以扩展原型方法或创建几个附加方法。但我们谈论的是基础映射器,其中只有基础方法应该是
    【解决方案2】:

    所以,您需要一个真正简化的 PHP 框架。数据映射器听起来像是过度设计。

    多年来,我用 PHP 制作了一些 KISS 框架,这就是我所做的:

    • 使用模板(又名视图),例如Smarty。非常适合外包您的网页设计。
    • 创建一个名为 pages 的文件夹(又名控制器)。页面仅由 index.php 调用。
    • 创建一个名为 models 的文件夹。只有模型与您的数据库对话。
    • 制作一个 index.php(又名路由器)。有一个?page=dog 参数。

    严格的 MCV(又名 MVC)术语不是圣杯,以上是简单网站/应用程序/CMS 的一个很好的实现。

    零件

    /pages/page_dog.inc.php 一个页面加载他需要的模型,操作并显示它:

    <?php if(!defined('YOURFRAMEWORK')){die('External access denied');}
    
    // Page init
    require './models/model_dog.inc.php';
    
    $id = $_GET['id']; // todo fix injection attacks
    
    $ModelDog = new ModelDog($DB);
    
    // Page main
    $ModelDog->Load($id);
    echo $ModelDog->item['breed'];
    

    对于列表(用户选择$id 的页面),您可能不希望单独的模型代表每个结果。改为创建一个列表器类,与模型非常相似,但在一个数组中返回多个项目。 DRY 并让 ListerDog 类使用 ModelDog 很诱人,但没有可读性提升,只是性能上的痛苦。

    /index.php(又名路由器)在 auth 和 init ($DB) 之后调用页面(通过 require_once()):

    <?php
    
    define('YOURFRAMEWORK', 1); // disable "External access denied" error.
    
    require_once('config.inc.php'); // todo have this hold the $config[] array.
    
    $DB = @new mysqli( // or your derative, so you can log each query() call.
      $config['db']['host'],
      $config['db']['user'],
      $config['db']['pasw'],
      $config['db']['database']
    );
    if ($DB->connect_error) { die('db error: ' . mysqli_connect_errno()); }
    
    // Load page requested by user. For now, its dog hardcoded.
    require_once('./pages/page_dog.inc.php');
    
    $DB->close;
    

    /models/model_dog.inc.php(又名模型)为您与数据库对话、处理和清理数据。我也用这个put表单处理函数。

    <?php if(!defined('YOURFRAMEWORK')){die('External access denied');}
    
    class ModelDog extends BaseModel {
      private $tablename = 'dogs';
    
      /**
       * Load last (or specific) item.
       * @param integer $id
       * @return boolean Returns false when failed.
       */
      public function Load($id=null) {
        $query = "SELECT * FROM `".$this->tablename."` WHERE `id`='".$this->DB->Sanitize($id)."';";
        // TODO ..  $this->item =
      }
    
      public function ItemDefaults() {
        return array(
          'id' => 0,
          'breed' => 'unknown',
          'height' => 0
        );
      }
    
      // TODO ..
    
    }
    

    /models/basemodel.inc.php 扩展每个模型类,例如:

    abstract class BaseModel
    {
      protected $item = array(); // Here is all the data!
      protected $DB = null;
    
      public function __construct($aQDB) {
        parent::__construct();
        $this->DB = $aDB;
        $this->Reset();
      }
    
      public function Reset() {
        $this->item = ItemDefaults();
      }
    
      public function Item() { return $item; }
    
      // As seen in dog
      abstract public function Load($id);
      abstract public function ItemDefaults();
    
      // But descendants (models) must also implement:     
      abstract public function Save($id = NULL);
      abstract public function Delete($id);
      // You may want to add Validate() and other internal things here.
    }
    

    当我需要另一个小型框架时,以上所有内容都是我自己构建的最低版本。 你在适当的子类化中获得更多,而不是让更多的类做更多的事情。网站本质上是一件简单的事情,直到它变得过于复杂..

    要点/TLDR;

    如果您真的想要一个真正简化的 PHP 框架,请不要阅读太多。只需编写代码,您就会发现它需要什么才能让您更好地工作。

    【讨论】:

    • 也许我把事情复杂化了...我想我会放弃数据映射器,只使用带有 CRUD 函数的继承思想...我喜欢不要阅读太多的建议(这往往会减慢我的速度,现在我已经基本掌握了我只想完成项目的事情)......感谢建议和代码示例:)
    • 确实你明白了。您知道解决方案存在这一事实并不意味着您必须应用它们。我发现自己很难申请,但它是可靠的建议。
    • 我最喜欢的 DIY 框架就是这样,只有 2 种更重要的对象:Listers,以及一个累积 Model Validate() 和 LoadFromFormParams() 的 UserMessageLog。如果需要,该页面可以输出 UserMessageLog。如果某些页面需要专门的功能,它可以包含并使用库本身。框架保持相当简单,它只是一个附加东西的钉子。
    • 一个开发人员的过度工程是另一个开发人员急需的抽象。数据映射器是一种简单的模式,当然并没有过度设计,但是,它被许多框架和库广泛使用。此外,听起来像Validate() 应该在Validator 复合或类似的类似SoC 中,并且UserMessageLog() 通过AOP 装饰。不是太复杂,但如果你想做 OOP,那就去做吧 :-) 最后,模型是一个,我们没有模型。另外,请使用作曲家进行自动加载!你会喜欢它,它会为你节省这么多时间,你只需要 1 次。
    猜你喜欢
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    相关资源
    最近更新 更多