[php]标记对象

        在Mapper中查找一个对象(findById)或者查找所有相关的对象(findAll())很简单,但要查找符合特定条件的对象时就需要创建特定的SQL语句来实现查询了。

        比如查找user表中score大于10,查找user表中age等于18的Sql语句:

SELECT * FROM `user` WHERE `score` > 10;
SELECT * FROM `user` WHERE `age` = 18;
        虽然我们可以创建很多不同的SQL语句来实现,但这不够灵活,而且会产生重复代码。

        那么我们可以使用标记对象来实现比较灵活的条件查询。

        标记对象(Identity Object,也叫数据传输对象DTO):封装了数据库查询的中的条件,这样不同的条件可以在运行时构成不同的数据库Sql语句。

        比如可以用如下代码构建上面两条Select语句的Where部分:

$identityObject->field('score')->gt(10);
$identityObject->field('age')->eq(18);
        

         下面为实现代码:

         Field类:

/**
 * 字段域类 
 * @author happen
 */
class Field {
	// 字段名
	private $name = null;
	// 比较条件
	private $comp = array();
	
	public function __construct($name) {
		$this->name = $name;
	}
	
	public function addTest($operator, $value) {
		$this->comp[] = array('name' => $this->name, 'operator' => $operator, 'value' => $value);
	}
	
	public function getComps() {
		return $this->comp;
	}
	
	public function isIncomplete() {
		return empty($this->comp);
	}
}
      

        IdentityObject类:

namespace demo\mapper;

/**
 * 标记对象,也叫DTO
 * @author happen
 *
 */
class IdentityObject {
	protected $fields = array();
	protected $currentField = null;
	protected $enforce = array();
	
	public function __construct($field = null, $enforce = null) {
		if (!is_null($enforce)) {
			$this->enforce = $enforce;
		}
		
		if (!is_null($field)) {
			$this->field($field);
		}
	}
	
	/**
	 *  添加字段
	 * @param string $fieldName
	 * @throws Exception
	 */
	public function field($fieldName) {
		if (!$this->isVoid() && $this->currentField->isIncomplete()) {
			// 字段不为空且字段条件不完整
			throw new Exception('Incomplete field');
		}
		$this->enforceField($fileName);
		
		// 添加字段
		if (isset($this->fields[$fieldName])) {
			$this->currentField = $this->fields[$fieldName];
		} else {
			$this->currentField = new Field($fieldName);
			$this->fields[$fieldName] = $this->currentField;
		}
		
		return $this;
	}
	
	public function eq($value) {
		return $this->opeartor('=', $value);
	}
	
	public function gt($value) {
		return $this->opeartor('>', $value);
	}
	
	public function lt($value) {
		return $this->opeartor('<', $value)	;
	}
	
	/**
	 * 给字段添加操作
	 * @param string $symbol
	 * @param string $value
	 * @throws Exception
	 */
	private function opeartor($symbol, $value) {
		if ($this->isVoid()) {
			throw new Exception('no object fileds defined!');
		}
		
		$this->currentField->addTest($symbol, $value);
		return $this;
	} 
	
	public function isVoid() {
		return empty($this->fields);
	}
	
	/**
	 * 检验字段是否合法
	 * @param string $fileName
	 * @throws Exception
	 */
	public function enforceField($fileName) {
		if (!in_array($fileName, $this->enforce) && !empty( $this->enforce)) {
			// 非法字段
			$forcelist = implode( ', ', $this->enforce );
            throw new Exception("{$fileName} not a legal field ($forcelist)");
		}
	}
	
	/**
	 * 得到对象的字段
	 */
	public function getObjectFields() {
		return $this->enforce;
	}
	
	/**
	 * 得到所有字段的条件查询
	 */
	public function getComps() {
		$ret = array();
        foreach ($this->fields as  $field) {
            $ret = array_merge($ret, $field->getComps());
        }
        
        return $ret;
	}
	
	public function __toString() {
		$ret = array();
        foreach($this->getComps() as $compdata) {
            $ret[] = "{$compdata['name']} {$compdata['operator']} {$compdata['value']}";
        }
        
        return implode( " AND ", $ret );
	}
}

       接下来就是一个使用例子:
$idobj = new IdentityObject();
$idobj->field("name")->eq("hello")->field("start")->gt(time())->lt(time()+(24*60*60))->getComps();
echo $idobj;
      输出结果为:
name = "hello" AND start > 1385127028 AND start < 1385213428

   

       一个具体的IdentityObject子类(强制了合法字段):

/**
 * ClassroomIdentityObject
 * @author happen
 *
 */
class ClassroomIdentityObject extends IdentityObject {
	public function __construct($field = null) {
		// 添加强制合法字段
		parent::__construct($filed, array('id', 'name'));
	}
}
        如果字段不合法,则会抛出异常。


        标记对象能够定义出各种SQL而不需要直接写SQL进行数据库查询,而且也对用户隐藏了数据库SQL细节,能够更灵活地组合出不同的查询条件。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值