PHP面向对象之领域模型+数据映射器实例(分析)

这里要说明一下 因为本人比较懒 博客中相关文章的内容更多的是对<深入PHP面向对象、模式与实践>一书中代码的整理和简单注解方便自己日后复习和参考,

对相关内容感兴趣的初学的朋友建议请先阅读原文。此处的内容只能当成一种学习的补充和参考。谢谢!

因原书中领域模型+数据映射器的示例代码是连贯在一起的 所以这里就整理在一起了。

简单介绍一下我的看法,从数据库操作的角度看领域模型主要是操作数据表中的单条记录的而数据映射器是操作整个数据表的数据的。

按原文的解释数据映射器是一个负责将数据库数据映射到对象的类,而领域模型象征着真实世界里项目中的各个参与者,它在数据中通常表现为一条记录。

废话不多说,代码和注解如下:

与领域模型相关的三个数据表结构分别为venue(场所)、space(空间)、event(事件)。

create table 'venue' (
   'id' int(11) not null auto_increment,
   'name' text,
   primary key ('id')
)
create table 'space' (
   'id' int(11) not null auto_increment,
   'venue' int(11) default null,
   'name' text,
   primary key ('id')
)
create table 'event' (
   'id' int(11) not null auto_increment,
   'space' int(11) default null,
   'start' mediumtext,
   'duration' int(11) default null,
   'name' text,
   primary key ('id')
)
//领域模型(这里只建了一个Venue类用于理解)
namespace woo\domain;

abstract class DomainObject{      //抽象基类
  
  private $id;
  
  function __construct ($id=null){
    $this->id = $id;
  }
  
  function getId(){
    return $this->id;
  }
  
  //原书没有具体实现,应该是用于获取对象的从属对象的,比如venue(场所)相关的space(空间)对象
  //具体的代码实现中应该从数据库中查询了相关数据并调用了Collection类,下面看到这个类的时候会有一个了解
  //而且这个方法的实现应该放在子类中才对
  static function getCollection($type){   
    return array();
  }
  
  function collection(){
    return self::getCollection(get_class($this));
  }
  
}

class Venue extends DomainObject {
  private $name;
  private $spaces;
  
  function __construct ($id = null,$name=null){
    $this->name= $name;
    $this->spaces = self::getCollection('\\woo\\domain\\space'); //这里应该证明了我上述的猜测
    parent::__construct($id);
  }
  
  function setSpaces(SpaceCollection $spaces){
    $this->spaces = $spaces;
  }
  
  function addSpace(Space $space){
    $this->spaces->add($space);
    $space->setVenue($this);
  }
  
  function setName($name_s){
    $this->name = $name_s;
    $this->markDirty();
  }
  
  function getName(){
    return $this->name;
  }
}


//数据映射器(正如原文的解释数据映射器是一个负责将数据库数据映射到对象的类)
namespace woo\mapper;

abstract class Mapper{      //抽象基类
  abstract static $PDO;    //操作数据库的pdo对象
  function __construct (){
    if(!isset(self::$PDO){
      $dsn = \woo\base\ApplicationRegistry::getDSN();
      if(is_null($dsn)){
        throw new \woo\base\AppException("no dns");
      }
      self::$PDO = new \PDO($dsn);
      self::$PDO->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION);
    }
  }
  
  function createObject($array){          //将数组创建为上述领域模型中的对象
    $obj = $this->doCreateObject($array);    //在子类中实现
    return $obj;
  }
  
  function find($id){                //通过ID从数据库中获取一条数据并创建为对象
    $this->selectStmt()->execute(array($id));
    $array= $this->selectStmt()->fetch();
    $this->selectStmt()->closeCursor();
    if(!is_array($array)){
      return null;
    }
    if(!isset($array['id'])){
      return null;
    }
    $object = $this->createObject($array);
    return $object;  
  }
  
  function insert(\woo\domain\DomainObject $obj){      //将对象数据插入数据库
    $this->doInsert($obj);
  }
  
  //需要在子类中实现的各抽象方法
  abstract function update(\woo\domain\DomainObject $objet);
  protected abstract function doCreateObject(array $array);
  protected abstract function selectStmt();
  protected abstract function doInsert(\woo\domain\DomainObject $object);
}

//这里只建立一个VenueMapper类用于理解
class VenueMapper extends Mapper {
  function __construct (){    
    parent::__construct();  //各种sql语句对象  
    $this->selectStmt = self::$PDO->prepare("select * from venue where id=?");
    $this->updateStmt = self::$PDO->prepare("update venue set name=?,id=? where id=?");
    $this->insertStmt = self::$PDO->prepare("insert into venue (name) values(?)");
  }
  
  protected function getCollection(array $raw){    //将Space数组转换成对象
    return new SpaceCollection($raw,$this);      //这个类的基类在下面    
  }
  
  protected function doCreateObject (array $array){  //创建对象
    $obj = new \woo\domain\Venue($array['id']);
    $obj->setname($array['name']);
    return $obj;
  }
  
  protected function doInsert(\woo\domain\DomainObject $object){ //将对象插入数据库
    print 'inserting';
    debug_print_backtrace();
    $values = array($object->getName());
    $this->insertStmt->execute($values);
    $id = self::$PDO->lastInsertId();
    $object->setId($id);
  }
  
  function update(\woo\domain\DomainObject $object){    //修改数据库数据
    print "updation\n";
    $values = array($object->getName(),$object->getId(),$object->getId());
    $this->updateStmt->execute($values);
  }
  
  function selectStmt(){          //返回一个sql语句对象
    return $this->selectStmt;
  }
  
}

Iterator接口定义的方法:

rewind()            指向列表开头   
current()            返回当前指针处的元素
key()                返回当前的键(比如,指针的指)
next()               
valid()

下面这个类是处理多行记录的,传递数据库中取出的原始数据和映射器进去,然后通过数据映射器在获取数据时将其创建成对象

abstract class Collection implements \Iterator{
  protected $mapper;      //数据映射器
  protected $total = 0;    //集合元素总数量
  protected $raw = array();  //原始数据
  
  private $result;
  private $pointer = 0;    //指针
  private $objects = array();  //对象集合
  
  function __construct (array $raw = null,Mapper $mapper= null){
    if(!is_null($raw)&& !is_null($mapper)){
      $this->raw = $raw;
      $this->total = count($raw);
    }
    $this->mapper = $mapper;
  }
  
  function add(\woo\domain\DmainObject $object){  //这里是直接添加对象
    $class = $this->targetClass();
    if(!($object instanceof $class)){
      throw new Exception("This is a {$class} collection");
    }
    $this->notifyAccess();
    $this->objects[$this->total] = $object;
    $this->total ++;
  }
  
  abstract function targetClass();  //子类中实现用来在插入对象时检查类型的
  
  protected function notifyAccess(){  //不知道干嘛的
    
  }
  
  private function getRow($num){    //获取集合中的单条数据,就是这里通过数据映射器将数据创建成对象
    $this->notifyAccess();
    if($num >= $this->total || $num < 0){
      return null;
    }
    if(isset($this->objects[$num]){
      return $this->objects[$num];
    }
    if(isset($this->raw[$num]){
      $this->objects[$num] = $this->mapper->createObject($this->raw[$num]);
      return $this->objects[$num];
    }
  }
  
  public function rewind(){      //重置指针
    $this->pointer = 0;
  }
  
  public function current(){      //获取当前指针对象
    return $this->getRow($this->pointer);
  }
  
  public function key(){        //获取当前指针
    return $this->pointer;
  }
  
  public function next(){      //获取当前指针对象,并将指针下移  
    $row = $this->getRow($this->pointer);
    if($row){$this->pointer ++}
    return $row;
  }
  
  public function valid(){    //验证
    return (!is_null($this->current()));
  }
  
}

//子类
class VenueColletion extends Collection implements \woo\domain\VenueCollection{
  function targetClass(){
    return "\woo\domain\Venue";
  }
}


//客户端
$mapper = new \woo\mapper\VenueMapper();
$venue = $mapper->find(12);
print_r($venue);

$venue = new \woo\domain\Venue();
$venue->setName("the likey lounge-yy");
//插入对象到数据库
$mapper->insert($venue);
//从数据库中读出刚才插入的对象
$venue = $mapper->find($venue->getId());
print_r($venue);

//修改对象
$venue->setName("the bibble beer likey lounge-yy");
//调用update来更新记录
$mapper->update($venue);
//再次读出对象数据
$venue = $mapper->find($venue->getId());
print_r($venue);


//结束

以上这篇PHP面向对象之领域模型+数据映射器实例(分析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。