/*选择工厂和更新工厂模式,这个模式的类(UpdateFactory和SelectionFactory类)就是用来创建SQL语句的. 因为涉及到之前学习的内容比较多,这里就尽量将之前相关模式的示例代码放在一起来进行学习和回顾了。 以下的代码都是代码片段而且涉及到连接数据库,无法进行整体的调试(某些部分单独拿出来的话就可以),因此重在理解。*///更新工厂abstract class UpdateFactory{ abstract function newUpdate(\woo\domain\DomainObject $obj); //拼接更新或插入的sql语句protected function buildStatement($table,array $fields ,array $condition = null){$terms = array(); //SQL语句中占位符所代表的实际值if(!is_null($condition)){ //有条件则拼接更新语句,无条件则拼接插入语句$query = "UPDATE {$table} SET";$query .= implode(" = ? " ,array_keys($fields)) . " = ? ";$terms = array_values($fields);$cond = array();$query .= " WHERE ";foreach($condition as $key=>$val){$cond[] = " $key = ? ";$terms[] = $val; }$query .= implode(" AND ",$cond); } else {$query = " INSERT INTO {$table} (";$query .= implode(",",array_keys($fields));$query .= " ) VALUES ( ";foreach($fields as $name => $value){$terms[] = $value;$qs[] = "?"; }$query .= implode(",",$qs);$query .=" ) "; }return array($query,$terms); } }//通过领域模型生成SQL语句class VenueUpdateFactory extends UpdateFactory{function newUpdate(\woo\domain\DomainObject $obj){$id = $obj->getId();$cond = null;$values['name'] = $obj->getName();if($id > -1 ){$cond["id"] = $id; }return $this->buildStatement("venue",$values,$cond); } }//选择工厂abstract class SelectionFactory{abstract function newSelection(IdentityObject $obj); //通过标识对象拼接sql语句的where条件语句function buildWhere (IdentityObject $obj){if($obj->isVoid){return array("",array()); }$compstrings = array();$values = array();foreach($obj->getComps() as $comp){$compstrings[] = "{$comp['name']} {$comp['operator']} ?";$values[] = $comp['value']; }$where = " WHERE " . implode(" AND ",$compstrings);return array($where,$values); } }//拼接select语句class VenuSelectionFactory extends SelectionFactory {function newSelection(IdentityObject $obj){$field = implode(',',$obj->getObjectFields());$core = "SELECT $fields FROM venue";list($where,$values) = $this->buildWhere($obj);return array($core." ".$where,$values); } } //现在来回顾一下之前学习过的相关知识//字段对象class Field {protected $name = null; //字段名称protected $operator = null; //操作符 protected $comps = array(); //存放条件的数组 protected $incomplete = false; //检查条件数组是否有值function __construct ($name){$this->name= $name; } //添加where 条件function addTest($operator,$value){$this->comps[] = array('name'=>$this->name,'operator'=>$operator,'value'=>$value); } //获取存放条件的数组function getComps(){return $this->comps; } function isIncomplete(){return empty($this->comps); } }//标识对象,主要功能就是拼接where条件语句class IdentityObject {protected $currentfield = null; //当前操作的字段对象protected $fields = array(); //字段对象集合private $and = null;private $enforce = array(); //限定的合法字段 function __construct($field = null, array $enforce = null){if(!is_null($enforce)){$this->enforce = $enforce; }if(!is_null($field)){$this->field($field); } } //获取限定的合法字段function getObjectFields(){return $this->enforce; } //主要功能为设置当前需要操作的字段对象function field($fieldname){if(!$this->isVoid()&& $this->currentfield->isIncomplete()){throw new \Exception("Incomplete field"); }$this->enforceField($fieldname);if(isset($this->fields[$fieldname]){$this->currentfield = $this->fields[$fieldname]; } else {$this->currentfield = new Field($fieldname);$this->fields[$fieldname] = $this->currentfield; }return $this; //采用连贯语法 } //字段集合是否为空function isVoid(){return empty($this->fields); } //检查字段是否合法function enforceField ($fieldname){if(!in_array($fieldname,$this->enforce) && !empty($this->enforce)){$forcelist = implode(',',$this->enforce);throw new \Exception("{$fieldname} not a legal field {$forcelist}"); } } //向字段对象添加where条件function eq($value){return $this->operator("=",$value); } function lt($value){return $this->operator("<",$value); } function gt($value){return $this->operator(">",$value); } //向字段对象添加where条件private function operator($symbol,$value){if($this->isVoid){throw new \Exception("no object field defined"); }$this->currentfield->addTest($symbol,$value);return $this; //采用连贯语法 } //获取此类中所有字段对象集合的where条件数组function getComps(){$ret = array();foreach($this->fields as $key => $field){$ret = array_merge($ret,$field->getComps()); }return $ret; } }//数据映射器class DomainObjectAssembler {protected static $PDO; //PersistenceFactory本例中并未实现,按原书的说法读者自己完成 //其主要功能就是生成相应类型的选择工厂类、更新工厂类或Collection对象 //在初始化的时候根据传入的PersistenceFactory对象决定了这个类是映射那个数据库表和领域模型的function __construct (PersistenceFactory $factory){$this->factory = $factory;if(!isset(self::$PDO)){$dsn = \woo\base\ApplicationRegistry::getDSN();if(is_null($dsn)){throw new \woo\base\AppException("NO DSN"); } self::$PDO = new \PDO ($dsn); self::$PDO->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); } } //获取预处理对象,用sql语句本身做为对象数组的键function getStatement($str){if(!isset($this->statements[$str])){$this->statements[$str] = self::$PDO->prepare($str); }return $this->statements[$str]; } //根据where条件返回一条数据function findOne(IdentityObject $idobj){$collection = $this->find($idobj);return $collection->next(); } //根据where条件返回一个数据集合function find(IdentityObject $idobj){$selfact = $this->factory->getSelectionFactory(); //获取选择工厂对象list($selection,$values) = $selfact->newSelection($idobj); //获取sql语句$stmt = $this->getStatement($selection); //获取预处理对象$stmt->execute($values); $raw = $stmt->fetchAll();return $this->factory->getCollection($raw); //还记得Collection对象吗,下面粘出代码回顾一下 } //根据where条件插入或更新一条数据function insert(\woo\domain\DomainObject $obj){$upfact = $this->factory->getUpdateFactory(); //获取更新工厂对象list($update,$values) = $upfact->newUpdate($obj); //获取sql语句$stmt = $this->getStatement($update); //获取预处理对象$stmt->execute($values);if($obj->getId()<0){ $obj->setId(self::$PDO->lastInsertId); }$obj->markClean(); } }/*这里在回顾一下Collection类,当然这个类和上面使用的Collection类是有差别的,因为至少这里的Mapper类与之前相比发生了一些变化 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"; } }//客户端 //初始化一个能够获取venue类型的选择工厂类、更新工厂类或Collection对象的超级工厂类$factory = \woo\mapper\PersistenceFactory::getFactory("woo\\domain\\Venue"); $finder = new \woo\mapper\DomainObjectAssembler($factory); //数据映射器$idobj = $factory->getIdentityObject()->field('name')->eq('The Eyeball Inn'); //设置where条件语句$collection = $finder->find($idobj); //根据where条件查找一个数据集合(一个Collection对象)foreach($collection as $venue){ print $venue->getName()."\n"; }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!