目前项目中选用的开发框架是Laravel4,经过几天的阅读源码以及看社区教程,发现是比较先进和强大的框架.
只是对新手入门这块做的很不给力,虽然官方文档在中文化上比较完整,但是相应的文档都是浅尝辄止,项目中用到的东西讲到的都比较少....
为了方便开发测试,所以把firephp予以集成,具体读源码找文档的时间就不说了,大致如下,在 app/start/global.php 文件中加入行:
Log::getMonolog()->pushHandler(new FirePHPHandler(Logger::DEBUG));
然后在代码中使用Log类就能输出结果...
另外对其db查询器使用不是很赶趟,项目组中的妹子也不会用,所以我把AertDb单独领出来做成了插件形式...
<?php /** * laravel Db 简化类 * * @author xuxiaohan */ class Aert_DbRepo { private static $_ds_instances = array(); /** * 为特定存储域选择匹配的存储服务实例 * * @param string $domain * * @return Aert_Db_Query */ static function queryNode($domain='') { $name = empty($domain) ? 'default' : trim($domain); if (!isset(self::$_ds_instances[$name])) { $dbo = empty($domain) ? DB::connection() : DB::connection($domain); self::$_ds_instances[$name] = new Aert_Db_Query($dbo); } return self::$_ds_instances[$name]; } /** * 返回数据库可以接受的日期格式 * * @param int $timestamp * @return string */ static function dbTimeStamp($timestamp) { return date('Y-m-d H:i:s', $timestamp); } /** * 打印输出结果 * * @param mixed $vars * @param string $label * @param bool $return * * @return String */ static function dump($vars, $label = '', $return = false) { $content = "<pre>\n"; if ($label != '') { $content .= "<strong>{$label} :</strong>\n"; } $content .= htmlspecialchars(print_r($vars, true),ENT_COMPAT | ENT_IGNORE); $content .= "\n</pre>\n"; if ($return) { return $content; } echo $content; } } /** * 查询接口 */ class Aert_Db_Query { /** * Db_Actor 对象 * * @var Aert_Db_Actor */ private $actor; function __construct($dbo) { $this->dbo = $dbo; $this->ds = new Aert_Db_DataSource( $dbo->getPdo() ); $this->actor = new Aert_Db_Actor($this->ds); } /** * 返回数据源对象 * * @return Aert_Db_DataSource */ function getDataSource() { return $this->ds; } /** * 从表中检索符合条件的一条记录 * * @param string $table * @param mixed $cond * @param string $fields * @param string $sort * * @return array */ function selectRow($table ,$cond=null ,$fields='*', $sort=null) { $cond = Aert_Db_SqlHelper::parseCond($this->ds,$cond); if ($cond) $cond = "WHERE {$cond}"; if ($sort) $sort = "ORDER BY {$sort}"; $qfields = Aert_Db_SqlHelper::qfields($fields,$table); return $this->actor->read(Aert_Db_Actor::MODE_READ_GETROW, array( "SELECT {$qfields} FROM {$table} {$cond} {$sort}" )); } /** * 从表中检索符合条件的多条记录 * * @param string $table * @param mixed $cond * @param string $fields * @param string $sort * @param int|array $limit 数组的话遵循格式 ( offset,length ) * @param bool $calc_total 计算总个数 * * @return array */ function select($table, $cond=null, $fields='*', $sort=null, $limit=null, $calc_total=false) { $cond = Aert_Db_SqlHelper::parseCond($this->ds,$cond); if ($cond) $cond = "WHERE {$cond}"; if ($sort) $sort = "ORDER BY {$sort}"; $qfields = Aert_Db_SqlHelper::qfields($fields,$table); $table = Aert_Db_SqlHelper::qtable($table); return $this->actor->read(Aert_Db_Actor::MODE_READ_GETALL, array( "SELECT {$qfields} FROM {$table} {$cond} {$sort}", empty($limit) ? false : $limit, $calc_total )); } /** * 统计符合条件的记录的总数 * * @param string $table * @param mixed $cond * @param string|array $fields * @param boolean $distinct * * @return int */ function count($table, $cond=null, $fields='*', $distinct=false) { if ($distinct) $distinct = 'DISTINCT '; $cond = Aert_Db_SqlHelper::parseCond($this->ds,$cond); if ($cond) $cond = "WHERE {$cond}"; if (is_null($fields) || trim($fields) == '*') { $fields = '*'; } else { $fields = Aert_Db_SqlHelper::qfields($fields,$table); } $table = Aert_Db_SqlHelper::qtable($table); return (int) $this->actor->read(Aert_Db_Actor::MODE_READ_GETONE, array( "SELECT COUNT({$distinct}{$fields}) FROM {$table} {$cond}" )); } /** * 插入一条记录 * * @param string $table * @param array $row * @param bool $pkval 是否获取插入的主键值 * * @return mixed */ function insert($table, array $row, $pkval=false) { list($holders, $values) = Aert_Db_SqlHelper::placeholder($row); $holders = implode(',', $holders); $fields = Aert_Db_SqlHelper::qfields(array_keys($values)); $table = Aert_Db_SqlHelper::qtable($table); return $this->actor->write(Aert_Db_Actor::MODE_WRITE_INSERT, array( Aert_Db_SqlHelper::bind($this->ds, "INSERT INTO {$table} ({$fields}) VALUES ({$holders})", $row), $pkval )); } /** * 更新表中记录 * * @param string $table * @param array $row * @param mixed $cond 条件 * * @return int */ function update($table, array $row, $cond=null) { if ( empty($row) ) return false; list($pairs, $values) = Aert_Db_SqlHelper::placeholderPair($row); $pairs = implode(',', $pairs); $table = Aert_Db_SqlHelper::qtable($table); $sql = Aert_Db_SqlHelper::bind($this->ds, "UPDATE {$table} SET {$pairs}", $row); $cond = Aert_Db_SqlHelper::parseCond($this->ds, $cond); if ($cond) $sql .= " WHERE {$cond}"; return $this->actor->write(Aert_Db_Actor::MODE_WRITE_UPDATE, array( $sql )); } /** * 删除 表中记录 * * @param string $table * @param mixed $cond * * @return int */ function del($table, $cond=null) { $cond = Aert_Db_SqlHelper::parseCond($this->ds, $cond); $table = Aert_Db_SqlHelper::qtable($table); $sql = "DELETE FROM {$table} " . (empty($cond) ? '' : "WHERE {$cond}"); return $this->actor->write(Aert_Db_Actor::MODE_WRITE_DELETE, array( $sql )); } /** * 向表中 某字段的值做 "加"运算 * * @param string $table * @param string $field * @param int $incr * @param mixed $cond * * @return int */ function incrField($table, $field, $incr=1, $cond=null) { if ( empty($field) ) return false; $table = Aert_Db_SqlHelper::qtable($table); $field = Aert_Db_SqlHelper::qfield($field); $sql = "UPDATE {$table} SET {$field}={$field}+{$incr}"; $cond = Aert_Db_SqlHelper::parseCond($this->ds, $cond); if ($cond) $sql .= " WHERE {$cond}"; return $this->actor->write(Aert_Db_Actor::MODE_WRITE_UPDATE, array( $sql )); } } class Aert_Db_Actor { /** * 读 记录集 */ const MODE_READ_GETALL = 1; /** * 读 第一条记录 */ const MODE_READ_GETROW = 2; /** * 读 第一条记录的第一个字段 */ const MODE_READ_GETONE = 3; /** * 读 记录集的指定列 */ const MODE_READ_GETCOL = 4; /** * 读 记录集的总个数 */ const MODE_READ_ALLCOUNT = 5; /** * 写 (插入) 操作 */ const MODE_WRITE_INSERT = 11; /** * 写 (更新) 操作 */ const MODE_WRITE_UPDATE = 12; /** * 写 (删除) 操作 */ const MODE_WRITE_DELETE = 13; /** * 数据源对象 * * @var Aert_Db_DataSource */ private $ds; function __construct(Aert_Db_DataSource $ds) { $this->ds = $ds; } /** * 执行 读 操作 * * @param string $mode 模式 [MODE_READ_GETALL,MODE_READ_GETROW,MODE_READ_GETONE,MODE_READ_GETCOL] * @param mixed $arguments 参数[不同模式参数不同,缺省为sql字符串] * @param callback $cb 查询记录集的回调处理函数 * * @return mixed */ function read($mode, $arguments, $cb=NULL){ $arguments = (array) $arguments; $sql = array_shift($arguments);// 缺省第一个参数是sql字符串 switch ($mode){ case self::MODE_READ_GETALL: // array(sql,limit,counter),如果sql里面带了limit则不能使用counter $limit = array_shift($arguments); $counter = array_shift($arguments); $result = null; if ($counter) { $result = array( 'total' => $this->ds->count($sql), ); } if ($limit) $sql = $this->ds->sql_limit($sql, $limit); if (is_array($result)) { $result['rows'] = ($result['total'] == 0) ? array() : $this->ds->all($sql); } else { $result = $this->ds->all($sql); } break; case self::MODE_READ_GETCOL:// array(sql,col,limit,counter) col 下标从 0开始 为第一列 $col = (int) array_shift($arguments); $limit = array_shift($arguments); $counter = array_shift($arguments); $result = null; if ($counter) { $result = array( 'total' => $this->ds->count($sql), ); } if ($limit) $sql = $this->ds->sql_limit($sql, $limit); if (is_array($result)) { $result['rows'] = ($result['total'] == 0) ? array() : $this->ds->col($sql,$col); } else { $result = $this->ds->col($sql,$col); } break; case self::MODE_READ_GETROW: $result = $this->ds->row($sql); break; case self::MODE_READ_GETONE: $result = $this->ds->one($sql); break; case self::MODE_READ_ALLCOUNT: $result = $this->ds->count($sql); break; default: throw Exception("无效[r]: {$mode}"); } return (empty($cb) || !is_callable($cb)) ? $result : call_user_func_array($cb,array($result)); } /** * 执行 更新/删除 操作 * * @param string $mode 模式 [MODE_WRITE_INSERT,MODE_WRITE_UPDATE,MODE_WRITE_DELETE] * @param mixed $arguments 参数[不同模式参数不同,缺省为sql字符串] * @param callback $cb 查询结果集的回调处理函数 * * @return mixed */ function write($mode, $arguments, $cb=NULL){ $arguments = (array) $arguments; $sql = array_shift($arguments);// 缺省第一个参数是sql字符串 $this->ds->execute($sql); switch ($mode){ case self::MODE_WRITE_INSERT: // 插入操作可选 得到主键标识 $id = array_shift($arguments); $result = $id ? $this->ds->insert_id() : $this->ds->affected_rows(); break; case self::MODE_WRITE_UPDATE: case self::MODE_WRITE_DELETE: $result = $this->ds->affected_rows(); break; default: throw Exception("无效[w]: {$mode}"); } return (empty($cb) || !is_callable($cb)) ? $result : call_user_func_array($cb,array($result)); } } /** * Db 数据源 */ class Aert_Db_DataSource { /** * @var int */ private $query_count = 0; /** * @var PDO */ private $db; /** * @var int */ protected $affected_rows = 0; function __construct(PDO $db) { $this->db = $db; } function begin() { $this->db->beginTransaction(); } function commit() { $this->db->commit(); } function rollback() { $this->db->rollBack(); } function qstr($value) { if (is_int($value) || is_float($value)) { return $value; } if (is_bool($value)) { return $value ? 1 : 0; } if (is_null($value)) { return 'NULL'; } return $this->db->quote($value); } function insert_id() { return $this->db->lastInsertId(); } function affected_rows() { return $this->affected_rows; } function execute($sql, array $args = null) { $this->affected_rows = 0; if (!empty($args)) { $sql = Aert_Db_SqlHelper::bind($this, $sql, $args); } Log::debug($sql); $result = $this->db->exec($sql); $this->query_count++; if ($result === false) { $error = $this->db->errorInfo(); throw new Exception("QUERY_FAILED: {$error[0]}/{$error[1]}, {$error[2]}\n{$sql}"); } $this->affected_rows = $result; } /** * @return PDOStatement */ private function query($sql) { Log::debug($sql); $statement = $this->db->query($sql); $this->query_count++; if ($statement !== false) return $statement; $error = $this->db->errorInfo(); throw new Exception("QUERY_FAILED: {$error[0]}/{$error[1]}, {$error[2]}\n{$sql}"); } function all($sql) { $res = $this->query($sql); /* @var $res PDOStatement */ $rowset = $res->fetchAll(PDO::FETCH_ASSOC); $res = null; return $rowset; } function one($sql) { $res = $this->query($sql); /* @var $res PDOStatement */ $val = $res->fetchColumn(0); $res = null; return $val; } function row($sql) { $res = $this->query($sql); /* @var $res PDOStatement */ $row = $res->fetch(PDO::FETCH_ASSOC); $res = null; return $row; } function col($sql, $col=0) { $res = $this->query($sql); /* @var $res PDOStatement */ $rowset = $res->fetchAll(PDO::FETCH_ASSOC,$col); $res = null; return $rowset; } function count($sql) { return (int) $this->one("SELECT COUNT(*) FROM ( $sql ) AS t"); } function sql_limit($sql, $limit) { if (empty($limit)) return $sql; if (is_array($limit)) { list($skip, $l) = $limit; $skip = intval($skip); $limit = intval($l); } else { $skip = 0; $limit = intval($limit); } return "{$sql} LIMIT {$skip}, {$limit}"; } } class Aert_Db_SqlHelper { /** * 根据 SQL 语句和提供的参数数组,生成最终的 SQL 语句 * * @param Aert_Db_DataSource $ds * @param string $sql * @param array $inputarr * * @return string */ static function bind(Aert_Db_DataSource $ds, $sql, array $inputarr) { $arr = explode('?', $sql); $sql = array_shift($arr); foreach ($inputarr as $value) { if (isset($arr[0])) { $sql .= $ds->qstr($value) . array_shift($arr); } } return $sql; } /** * 解析查询条件 * * @param Aert_Db_DataSource $ds * @param mixed $cond * @param bool $dash 是否使用括号将返回的条件包括起来 * * @return string */ static function parseCond(Aert_Db_DataSource $ds, $cond, $dash=false) { if (empty($cond)) return ''; // 如果是字符串,则假定为自定义条件 if (is_string($cond)) return $cond; // 如果不是数组,说明提供的查询条件有误 if (!is_array($cond)) return ''; static $equalIN = array('=','IN','NOT IN'); static $betweenAnd = array('BETWEEN_AND','NOT_BETWEEN_AND'); $where = '';$expr = ''; /** * 不过何种条件形式,一律为 字段名 => (值, 操作, 连接运算符, 值是否是SQL命令) 的形式 */ foreach ($cond as $field => $d) { $expr = 'AND'; if (!is_string($field)) { continue; } if (!is_array($d)) { // 字段名 => 值 $d = array($d); } reset($d); // 第一个元素是值 if (!isset($d[1])) { $d[1] = '='; } if (!isset($d[2])) { $d[2] = $expr; } if (!isset($d[3])) { $d[3] = false; } list($value, $op, $expr, $isCommand) = $d; $op = strtoupper(trim($op)); $expr = strtoupper(trim($expr)); if (is_array($value)){ do { if (in_array($op, $equalIN)){ if ($op == '=') $op = 'IN'; $value = '(' . implode(',',array_map(array($ds, 'qstr'),$value)) . ')'; break; } if (in_array($op, $betweenAnd)){ $between = array_shift($value); $and = array_shift($value); $value = sprintf('BETWEEN %s AND %s',$ds->qstr($between),$ds->qstr($and)); $op = 'NOT_BETWEEN_AND' == $op ? 'NOT' : '';// 此处已经串在 $value 中了 break; } // 一个字段对应 多组条件 的实现,比如 a > 15 OR a < 5 and a != 32 // 'a' => array( array( array(15,'>','OR'),array(5,'<','AND'), array(32,'!=') ) , 'FIELD_GROUP') if ($op == 'FIELD_GROUP'){ $kv = array(); foreach($value as $k => $v){ $kv[":+{$k}+:"] = $v; } $value = self::parseConditions($ds,$kv,true); foreach(array_keys($kv) as $k){ $value = str_ireplace($k,$field,$value); } $field = $op = '';// 此处已经串在 $value 中了 break; } } while(false); $isCommand = true; } if (!$isCommand) { $value = $ds->qstr($value); } $where .= "{$field} {$op} {$value} {$expr} "; } $where = substr($where, 0, - (strlen($expr) + 2)); return $dash ? "({$where})" : $where; } static function qtable($table) { return "`{$table}`"; } static function qfield($fieldName, $table = null) { $fieldName = ($fieldName == '*') ? '*' : "`{$fieldName}`"; return $table != '' ? self::qtable($table) . '.' . $fieldName : $fieldName; } static function qfields($fields, $table = null, $returnArray = false) { if (!is_array($fields)) { $fields = explode(',', $fields); $fields = array_map('trim', $fields); } $return = array(); foreach ($fields as $fieldName) { $return[] = self::qfield($fieldName, $table); } return $returnArray ? $return : implode(', ', $return); } static function placeholder(& $inputarr, $fields = null) { $holders = array(); $values = array(); if (is_array($fields)) { $fields = array_change_key_case(array_flip($fields), CASE_LOWER); foreach (array_keys($inputarr) as $key) { if (!isset($fields[strtolower($key)])) { continue; } $holders[] = '?'; $values[$key] =& $inputarr[$key]; } } else { foreach (array_keys($inputarr) as $key) { $holders[] = '?'; $values[$key] =& $inputarr[$key]; } } return array($holders, $values); } static function placeholderPair(& $inputarr, $fields = null) { $pairs = array(); $values = array(); if (is_array($fields)) { $fields = array_change_key_case(array_flip($fields), CASE_LOWER); foreach (array_keys($inputarr) as $key) { if (!isset($fields[strtolower($key)])) { continue; } $qkey = self::qfield($key); $pairs[] = "{$qkey}=?"; $values[$key] =& $inputarr[$key]; } } else { foreach (array_keys($inputarr) as $key) { $qkey = self::qfield($key); $pairs[] = "{$qkey}=?"; $values[$key] =& $inputarr[$key]; } } return array($pairs, $values); } }
<?php /** * AertDb表模型 CRUD 包装器 * * @author xuxiaohan */ class Aert_TObject { /** * 数据库链接节点名 * * 子类可以覆盖此属性 * * @var string */ protected $queryNode = ''; /** * 数据表名 * * 子类可以覆盖此属性 * * @var string */ protected $table; /** * 返回 对象实例 * * @param string $table * @param string $query_node * * @return Aert_TObject */ static function instance($table,$query_node='') { static $list = array(); $table = trim($table); if ( empty($table) ) return null; if (empty($list[$table])) { $list[$table] = new self(); $list[$table]->queryNode = $query_node; $list[$table]->table = $table; } return $list[$table]; } /** * 从表中检索符合条件的多条记录 * * @param mixed $cond * @param string $fields * @param string $sort * @param int|array $limit 数组的话遵循格式 ( offset,length ) * @param bool $calc_total 计算总个数 * * @return array */ function getAll($cond=null, $fields='*', $sort=null, $limit=null, $calc_total=false) { return Aert_DbRepo::queryNode($this->queryNode)->select($this->table,$cond, $fields, $sort, $limit, $calc_total); } /** * 从表中检索符合条件的一条记录 * * @param mixed $cond * @param string $fields * @param string $sort * * @return array */ function getOne($cond=null ,$fields='*', $sort=null) { return Aert_DbRepo::queryNode($this->queryNode)->selectRow($this->table,$cond, $fields, $sort); } /** * 统计符合条件的记录的总数 * * @param mixed $cond * @param string|array $fields * @param boolean $distinct * * @return int */ function count($cond=null, $fields='*', $distinct=false) { return Aert_DbRepo::queryNode($this->queryNode)->count($this->table,$cond, $fields, $distinct); } /** * 插入一条记录 * * @param array $row * @param bool $pkval 是否获取插入的主键值 * * @return mixed */ function insert(array $row, $pkval=false) { return Aert_DbRepo::queryNode($this->queryNode)->insert($this->table, $row, $pkval); } /** * 更新表中记录,返回表中被更新行数 * * @param array $row * @param mixed $cond 条件 * * @return int */ function update(array $row, $cond=null) { return Aert_DbRepo::queryNode($this->queryNode)->update($this->table, $row, $cond); } /** * 删除 表中记录,返回表中被删除行数 * * @param mixed $cond * * @return int */ function del($cond=null) { return Aert_DbRepo::queryNode($this->queryNode)->del($this->table, $cond); } /** * 向表中 某字段的值做 "加"运算 * * @param string $field * @param int $incr * @param mixed $cond * * @return int */ function incrField($field, $incr=1, $cond=null) { return Aert_DbRepo::queryNode($this->queryNode)->incrField($this->table, $field, $incr, $cond); } /** * 向表中 某字段的值做 "减"运算 * * @param string $field * @param int $incr * @param mixed $cond * * @return int */ function decrField($field, $decr=1, $cond=null) { return Aert_DbRepo::queryNode($this->queryNode)->incrField($this->table, $field, (-1 * $decr), $cond); } }
功能虽然木有那么强大,但是也应该能方便不少