资讯专栏INFORMATION COLUMN

【thinkphp3.x】ThinkPHP/Lib/Core/Model.class.php文件分析

geekidentity / 2365人阅读

摘要:模型类实现了和模式操作状态插入模型数据更新模型数据包含上面两种方式必须验证表单存在字段则验证表单值不为空则验证当前使用的扩展模型当前数据库操作对象主键名称数据表前缀模型名称数据库名称数据库配置数据表名不包含表前缀实际数据表名包含表前缀最近错

</>复制代码

  1. /**
  2. * ThinkPHP Model模型类
  3. * 实现了ORM和ActiveRecords模式
  4. * @category Think
  5. * @package Think
  6. * @subpackage Core
  7. * @author liu21st
  8. */
  9. class Model {
  10. // 操作状态
  11. const MODEL_INSERT = 1; // 插入模型数据
  12. const MODEL_UPDATE = 2; // 更新模型数据
  13. const MODEL_BOTH = 3; // 包含上面两种方式
  14. const MUST_VALIDATE = 1;// 必须验证
  15. const EXISTS_VALIDATE = 0;// 表单存在字段则验证
  16. const VALUE_VALIDATE = 2;// 表单值不为空则验证
  17. // 当前使用的扩展模型
  18. private $_extModel = null;
  19. // 当前数据库操作对象
  20. protected $db = null;
  21. // 主键名称
  22. protected $pk = "id";
  23. // 数据表前缀
  24. protected $tablePrefix = "";
  25. // 模型名称
  26. protected $name = "";
  27. // 数据库名称
  28. protected $dbName = "";
  29. //数据库配置
  30. protected $connection = "";
  31. // 数据表名(不包含表前缀)
  32. protected $tableName = "";
  33. // 实际数据表名(包含表前缀)
  34. protected $trueTableName = "";
  35. // 最近错误信息
  36. protected $error = "";
  37. // 数据表的所有字段信息
  38. protected $fields = array();
  39. // 数据信息
  40. protected $data = array();
  41. // 查询表达式参数
  42. protected $options = array();
  43. protected $_validate = array(); // 自动验证定义
  44. protected $_auto = array(); // 自动完成定义
  45. protected $_map = array(); // 字段映射定义
  46. protected $_scope = array(); // 命名范围定义
  47. // 是否自动检测数据表字段信息
  48. protected $autoCheckFields = true;
  49. // 是否批处理验证
  50. protected $patchValidate = false;
  51. // 链操作方法列表
  52. protected $methods = array("table","order","alias","having","group","lock","distinct","auto","filter","validate");
  53. /**
  54. * 架构函数
  55. * 取得DB类的实例对象 字段检查
  56. * @access public
  57. * @param string $name 模型名称
  58. * @param string $tablePrefix 表前缀
  59. * @param mixed $connection 数据库连接信息
  60. */
  61. public function __construct($name="",$tablePrefix="",$connection="") {
  62. // 模型初始化
  63. $this->_initialize();
  64. // 获取模型名称
  65. if(!empty($name)) {
  66. if(strpos($name,".")) { // 支持 数据库名.模型名的 定义
  67. //属性1-数据库名 属性2-模型表名(数据表名)
  68. list($this->dbName,$this->name) = explode(".",$name);
  69. }else{//模型名
  70. $this->name = $name;
  71. }
  72. }elseif(empty($this->name)){
  73. //模型名为空的情况
  74. $this->name = $this->getModelName();
  75. }
  76. // 设置表前缀,检查$tablePrefix表前缀参数是否为Null,注意:不是检查表前缀参数是否为空
  77. if(is_null($tablePrefix)) {// 如果表前缀参数为Null表示没有前缀
  78. $this->tablePrefix = "";//没有前缀的情况
  79. }elseif("" != $tablePrefix) {//如果表前缀参数不为空
  80. $this->tablePrefix = $tablePrefix;
  81. }else{
  82. //默认执行:如果类中未指定表前缀,那么将采用系统默认指定的表前缀
  83. $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C("DB_PREFIX");
  84. }
  85. // 数据库初始化操作
  86. // 获取数据库操作对象
  87. // 当前模型有独立的数据库连接信息
  88. $this->db(0,empty($this->connection)?$connection:$this->connection);
  89. }
  90. /**
  91. * 自动检测数据表信息
  92. * @access protected
  93. * @return void
  94. */
  95. protected function _checkTableInfo() {
  96. // 如果不是Model类 自动记录数据表信息
  97. // 只在第一次执行记录
  98. if(empty($this->fields)) {//默认执行
  99. // 如果数据表字段没有定义则自动获取
  100. //调试模式下不执行
  101. if(C("DB_FIELDS_CACHE")) {//字段缓存的启用
  102. $db = $this->dbName?$this->dbName:C("DB_NAME");//数据库名
  103. $fields = F("_fields/".strtolower($db.".".$this->name));
  104. if($fields) {
  105. $version = C("DB_FIELD_VERISON");
  106. if(empty($version) || $fields["_version"]== $version) {
  107. $this->fields = $fields;
  108. return ;
  109. }
  110. }
  111. }
  112. // 每次都会读取数据表信息
  113. $this->flush();
  114. }
  115. }
  116. /**
  117. * 获取字段信息并缓存
  118. * @access public
  119. * @return void
  120. */
  121. public function flush() {
  122. //$this->db:数据库驱动类Db,class.php实例化对象,查看$this->db()方法
  123. // 缓存不存在则查询数据表信息
  124. //var_dump($this->db);//DbMysql.class.php驱动类对象
  125. //setModel()方法为Db.class.php中方法
  126. //class DbMysql extends Db{}
  127. $this->db->setModel($this->name);
  128. //$this->getTableName():获取表名,如:think_user
  129. //getFields方法获取数据表每个字段的信息
  130. /**
  131. *[id] => Array(
  132. * [name] => id
  133. * [type] => smallint(4) unsigned
  134. * [notnull] =>
  135. * [default] =>
  136. * [primary] => 1
  137. * [autoinc] => 1
  138. * )
  139. */
  140. $fields = $this->db->getFields($this->getTableName());
  141. if(!$fields) { // 无法获取字段信息
  142. return false;
  143. }
  144. /**
  145. * Array(
  146. * [0] => id
  147. * [1] => title
  148. * [2] => content
  149. * [3] => create_time
  150. * )
  151. */
  152. $this->fields = array_keys($fields);
  153. $this->fields["_autoinc"] = false;
  154. //注意:循环的不是$this->fields
  155. foreach ($fields as $key=>$val){
  156. // 记录字段类型
  157. $type[$key] = $val["type"];//如:$type[id]=int
  158. if($val["primary"]) {
  159. $this->fields["_pk"] = $key;//主键字段,这里的$key为字段名
  160. if($val["autoinc"]) $this->fields["_autoinc"] = true;//自动增长
  161. }
  162. }
  163. // 记录字段类型信息
  164. $this->fields["_type"] = $type;//表中各个字段的类型
  165. if(C("DB_FIELD_VERISON")) $this->fields["_version"] = C("DB_FIELD_VERISON");
  166. // 2008-3-7 增加缓存开关控制
  167. //调试模式下,为禁用,即:不会缓存
  168. if(C("DB_FIELDS_CACHE")){
  169. // 永久缓存数据表信息
  170. $db = $this->dbName?$this->dbName:C("DB_NAME");
  171. F("_fields/".strtolower($db.".".$this->name),$this->fields);
  172. }
  173. }
  174. /**
  175. * 设置数据对象的值
  176. * @access public
  177. * @param string $name 名称
  178. * @param mixed $value 值
  179. * @return void
  180. */
  181. public function __set($name,$value) {
  182. // 设置数据对象属性
  183. $this->data[$name] = $value;
  184. }
  185. /**
  186. * 获取数据对象的值
  187. * @access public
  188. * @param string $name 名称
  189. * @return mixed
  190. */
  191. public function __get($name) {
  192. return isset($this->data[$name])?$this->data[$name]:null;
  193. }
  194. /**
  195. * 检测数据对象的值
  196. * @access public
  197. * @param string $name 名称
  198. * @return boolean
  199. */
  200. public function __isset($name) {
  201. return isset($this->data[$name]);
  202. }
  203. /**
  204. * 销毁数据对象的值
  205. * @access public
  206. * @param string $name 名称
  207. * @return void
  208. */
  209. public function __unset($name) {
  210. unset($this->data[$name]);
  211. }
  212. /**
  213. * 利用__call方法实现一些特殊的Model方法
  214. * @access public
  215. * @param string $method 方法名称
  216. * @param array $args 调用参数
  217. * @return mixed
  218. */
  219. public function __call($method,$args) {
  220. if(in_array(strtolower($method),$this->methods,true)) {
  221. // 连贯操作的实现
  222. $this->options[strtolower($method)] = $args[0];
  223. return $this;
  224. }elseif(in_array(strtolower($method),array("count","sum","min","max","avg"),true)){
  225. // 统计查询的实现
  226. $field = isset($args[0])?$args[0]:"*";
  227. return $this->getField(strtoupper($method)."(".$field.") AS tp_".$method);
  228. }elseif(strtolower(substr($method,0,5))=="getby") {
  229. // 根据某个字段获取记录
  230. $field = parse_name(substr($method,5));
  231. $where[$field] = $args[0];
  232. return $this->where($where)->find();
  233. }elseif(strtolower(substr($method,0,10))=="getfieldby") {
  234. // 根据某个字段获取记录的某个值
  235. $name = parse_name(substr($method,10));
  236. $where[$name] =$args[0];
  237. return $this->where($where)->getField($args[1]);
  238. }elseif(isset($this->_scope[$method])){// 命名范围的多带带调用支持
  239. return $this->scope($method,$args[0]);
  240. }else{
  241. throw_exception(__CLASS__.":".$method.L("_METHOD_NOT_EXIST_"));
  242. return;
  243. }
  244. }
  245. // 回调方法 初始化模型
  246. protected function _initialize() {}
  247. /**
  248. * 对保存到数据库的数据进行处理
  249. * @access protected
  250. * @param mixed $data 要操作的数据
  251. * @return boolean
  252. */
  253. protected function _facade($data) {
  254. // 检查非数据字段
  255. if(!empty($this->fields)) {
  256. foreach ($data as $key=>$val){
  257. if(!in_array($key,$this->fields,true)){
  258. unset($data[$key]);
  259. }elseif(is_scalar($val)) {
  260. // 字段类型检查
  261. $this->_parseType($data,$key);
  262. }
  263. }
  264. }
  265. // 安全过滤
  266. if(!empty($this->options["filter"])) {
  267. $data = array_map($this->options["filter"],$data);
  268. unset($this->options["filter"]);
  269. }
  270. $this->_before_write($data);
  271. return $data;
  272. }
  273. // 写入数据前的回调方法 包括新增和更新
  274. protected function _before_write(&$data) {}
  275. /**
  276. * 新增数据
  277. * @access public
  278. * @param mixed $data 数据
  279. * @param array $options 表达式
  280. * @param boolean $replace 是否replace
  281. * @return mixed
  282. */
  283. public function add($data="",$options=array(),$replace=false) {
  284. if(empty($data)) {
  285. // 没有传递数据,获取当前数据对象的值
  286. if(!empty($this->data)) {
  287. $data = $this->data;//数据对象中的数据
  288. // 重置数据
  289. $this->data = array();
  290. }else{
  291. $this->error = L("_DATA_TYPE_INVALID_");
  292. return false;
  293. }
  294. }
  295. // 分析表达式
  296. $options = $this->_parseOptions($options);
  297. // 数据处理
  298. $data = $this->_facade($data);//对保存到数据库中的数据进行处理
  299. if(false === $this->_before_insert($data,$options)) {
  300. return false;
  301. }
  302. // 写入数据到数据库
  303. /**
  304. * $options:默认值有下面两个
  305. * Array
  306. (
  307. [table] => think_form
  308. [model] => Form
  309. )
  310. */
  311. $result = $this->db->insert($data,$options,$replace);
  312. if(false !== $result ) {
  313. $insertId = $this->getLastInsID();
  314. if($insertId) {
  315. // 自增主键返回插入ID
  316. $data[$this->getPk()] = $insertId;
  317. $this->_after_insert($data,$options);
  318. return $insertId;
  319. }
  320. $this->_after_insert($data,$options);
  321. }
  322. return $result;
  323. }
  324. // 插入数据前的回调方法
  325. protected function _before_insert(&$data,$options) {}
  326. // 插入成功后的回调方法
  327. protected function _after_insert($data,$options) {}
  328. public function addAll($dataList,$options=array(),$replace=false){
  329. if(empty($dataList)) {
  330. $this->error = L("_DATA_TYPE_INVALID_");
  331. return false;
  332. }
  333. // 分析表达式
  334. $options = $this->_parseOptions($options);
  335. // 数据处理
  336. foreach ($dataList as $key=>$data){
  337. $dataList[$key] = $this->_facade($data);
  338. }
  339. // 写入数据到数据库
  340. $result = $this->db->insertAll($dataList,$options,$replace);
  341. if(false !== $result ) {
  342. $insertId = $this->getLastInsID();
  343. if($insertId) {
  344. return $insertId;
  345. }
  346. }
  347. return $result;
  348. }
  349. /**
  350. * 通过Select方式添加记录
  351. * @access public
  352. * @param string $fields 要插入的数据表字段名
  353. * @param string $table 要插入的数据表名
  354. * @param array $options 表达式
  355. * @return boolean
  356. */
  357. public function selectAdd($fields="",$table="",$options=array()) {
  358. // 分析表达式
  359. $options = $this->_parseOptions($options);
  360. // 写入数据到数据库
  361. if(false === $result = $this->db->selectInsert($fields?$fields:$options["field"],$table?$table:$this->getTableName(),$options)){
  362. // 数据库插入操作失败
  363. $this->error = L("_OPERATION_WRONG_");
  364. return false;
  365. }else {
  366. // 插入成功
  367. return $result;
  368. }
  369. }
  370. /**
  371. * 保存数据
  372. * @access public
  373. * @param mixed $data 数据
  374. * @param array $options 表达式
  375. * @return boolean
  376. */
  377. public function save($data="",$options=array()) {
  378. if(empty($data)) {
  379. // 没有传递数据,获取当前数据对象的值
  380. if(!empty($this->data)) {
  381. $data = $this->data;
  382. // 重置数据
  383. $this->data = array();
  384. }else{
  385. $this->error = L("_DATA_TYPE_INVALID_");
  386. return false;
  387. }
  388. }
  389. // 数据处理
  390. $data = $this->_facade($data);
  391. // 分析表达式
  392. $options = $this->_parseOptions($options);
  393. if(false === $this->_before_update($data,$options)) {
  394. return false;
  395. }
  396. if(!isset($options["where"]) ) {
  397. // 如果存在主键数据 则自动作为更新条件
  398. if(isset($data[$this->getPk()])) {
  399. $pk = $this->getPk();
  400. $where[$pk] = $data[$pk];
  401. $options["where"] = $where;
  402. $pkValue = $data[$pk];
  403. unset($data[$pk]);
  404. }else{
  405. // 如果没有任何更新条件则不执行
  406. $this->error = L("_OPERATION_WRONG_");
  407. return false;
  408. }
  409. }
  410. $result = $this->db->update($data,$options);
  411. if(false !== $result) {
  412. if(isset($pkValue)) $data[$pk] = $pkValue;
  413. $this->_after_update($data,$options);
  414. }
  415. return $result;
  416. }
  417. // 更新数据前的回调方法
  418. protected function _before_update(&$data,$options) {}
  419. // 更新成功后的回调方法
  420. protected function _after_update($data,$options) {}
  421. /**
  422. * 删除数据
  423. * @access public
  424. * @param mixed $options 表达式
  425. * @return mixed
  426. */
  427. public function delete($options=array()) {
  428. if(empty($options) && empty($this->options["where"])) {
  429. // 如果删除条件为空 则删除当前数据对象所对应的记录
  430. if(!empty($this->data) && isset($this->data[$this->getPk()]))
  431. return $this->delete($this->data[$this->getPk()]);
  432. else
  433. return false;
  434. }
  435. if(is_numeric($options) || is_string($options)) {
  436. // 根据主键删除记录
  437. $pk = $this->getPk();
  438. if(strpos($options,",")) {
  439. $where[$pk] = array("IN", $options);
  440. }else{
  441. $where[$pk] = $options;
  442. }
  443. $pkValue = $where[$pk];
  444. $options = array();
  445. $options["where"] = $where;
  446. }
  447. // 分析表达式
  448. $options = $this->_parseOptions($options);
  449. $result= $this->db->delete($options);
  450. if(false !== $result) {
  451. $data = array();
  452. if(isset($pkValue)) $data[$pk] = $pkValue;
  453. $this->_after_delete($data,$options);
  454. }
  455. // 返回删除记录个数
  456. return $result;
  457. }
  458. // 删除成功后的回调方法
  459. protected function _after_delete($data,$options) {}
  460. /**
  461. * 查询数据集
  462. * @access public
  463. * @param array $options 表达式参数
  464. * @return mixed
  465. */
  466. public function select($options=array()) {
  467. if(is_string($options) || is_numeric($options)) {
  468. // 根据主键查询
  469. $pk = $this->getPk();
  470. if(strpos($options,",")) {
  471. $where[$pk] = array("IN",$options);
  472. }else{
  473. $where[$pk] = $options;
  474. }
  475. $options = array();
  476. $options["where"] = $where;
  477. }elseif(false === $options){ // 用于子查询 不查询只返回SQL
  478. $options = array();
  479. // 分析表达式
  480. $options = $this->_parseOptions($options);
  481. return "( ".$this->db->buildSelectSql($options)." )";
  482. }
  483. // 分析表达式
  484. $options = $this->_parseOptions($options);
  485. $resultSet = $this->db->select($options);
  486. if(false === $resultSet) {
  487. return false;
  488. }
  489. if(empty($resultSet)) { // 查询结果为空
  490. return null;
  491. }
  492. $this->_after_select($resultSet,$options);
  493. return $resultSet;
  494. }
  495. // 查询成功后的回调方法
  496. protected function _after_select(&$resultSet,$options) {}
  497. /**
  498. * 生成查询SQL 可用于子查询
  499. * @access public
  500. * @param array $options 表达式参数
  501. * @return string
  502. */
  503. public function buildSql($options=array()) {
  504. // 分析表达式
  505. $options = $this->_parseOptions($options);
  506. return "( ".$this->db->buildSelectSql($options)." )";
  507. }
  508. /**
  509. * 分析表达式
  510. * @access proteced
  511. * @param array $options 表达式参数
  512. * @return array
  513. */
  514. protected function _parseOptions($options=array()) {
  515. if(is_array($options))
  516. $options = array_merge($this->options,$options);
  517. // 查询过后清空sql表达式组装 避免影响下次查询
  518. $this->options = array();
  519. if(!isset($options["table"]))
  520. // 自动获取表名
  521. $options["table"] = $this->getTableName();
  522. if(!empty($options["alias"])) {
  523. $options["table"] .= " ".$options["alias"];
  524. }
  525. // 记录操作的模型名称
  526. $options["model"] = $this->name;
  527. // 字段类型验证
  528. if(isset($options["where"]) && is_array($options["where"]) && !empty($this->fields)) {
  529. // 对数组查询条件进行字段类型检查
  530. foreach ($options["where"] as $key=>$val){
  531. $key = trim($key);
  532. if(in_array($key,$this->fields,true)){
  533. if(is_scalar($val)) {
  534. $this->_parseType($options["where"],$key);
  535. }
  536. }elseif("_" != substr($key,0,1) && false === strpos($key,".") && false === strpos($key,"|") && false === strpos($key,"&")){
  537. unset($options["where"][$key]);
  538. }
  539. }
  540. }
  541. // 表达式过滤
  542. $this->_options_filter($options);
  543. return $options;
  544. }
  545. // 表达式过滤回调方法
  546. protected function _options_filter(&$options) {}
  547. /**
  548. * 数据类型检测
  549. * @access protected
  550. * @param mixed $data 数据
  551. * @param string $key 字段名
  552. * @return void
  553. */
  554. protected function _parseType(&$data,$key) {
  555. $fieldType = strtolower($this->fields["_type"][$key]);
  556. if(false === strpos($fieldType,"bigint") && false !== strpos($fieldType,"int")) {
  557. $data[$key] = intval($data[$key]);
  558. }elseif(false !== strpos($fieldType,"float") || false !== strpos($fieldType,"double")){
  559. $data[$key] = floatval($data[$key]);
  560. }elseif(false !== strpos($fieldType,"bool")){
  561. $data[$key] = (bool)$data[$key];
  562. }
  563. }
  564. /**
  565. * 查询数据
  566. * @access public
  567. * @param mixed $options 表达式参数
  568. * @return mixed
  569. */
  570. public function find($options=array()) {
  571. if(is_numeric($options) || is_string($options)) {
  572. $where[$this->getPk()] = $options;
  573. $options = array();
  574. $options["where"] = $where;
  575. }
  576. // 总是查找一条记录
  577. $options["limit"] = 1;
  578. // 分析表达式
  579. $options = $this->_parseOptions($options);
  580. $resultSet = $this->db->select($options);
  581. if(false === $resultSet) {
  582. return false;
  583. }
  584. if(empty($resultSet)) {// 查询结果为空
  585. return null;
  586. }
  587. $this->data = $resultSet[0];
  588. $this->_after_find($this->data,$options);
  589. return $this->data;
  590. }
  591. // 查询成功的回调方法
  592. protected function _after_find(&$result,$options) {}
  593. /**
  594. * 处理字段映射
  595. * @access public
  596. * @param array $data 当前数据
  597. * @param integer $type 类型 0 写入 1 读取
  598. * @return array
  599. */
  600. public function parseFieldsMap($data,$type=1) {
  601. // 检查字段映射
  602. if(!empty($this->_map)) {
  603. foreach ($this->_map as $key=>$val){
  604. if($type==1) { // 读取
  605. if(isset($data[$val])) {
  606. $data[$key] = $data[$val];
  607. unset($data[$val]);
  608. }
  609. }else{
  610. if(isset($data[$key])) {
  611. $data[$val] = $data[$key];
  612. unset($data[$key]);
  613. }
  614. }
  615. }
  616. }
  617. return $data;
  618. }
  619. /**
  620. * 设置记录的某个字段值
  621. * 支持使用数据库字段和方法
  622. * @access public
  623. * @param string|array $field 字段名
  624. * @param string $value 字段值
  625. * @return boolean
  626. */
  627. public function setField($field,$value="") {
  628. if(is_array($field)) {
  629. $data = $field;
  630. }else{
  631. $data[$field] = $value;
  632. }
  633. return $this->save($data);
  634. }
  635. /**
  636. * 字段值增长
  637. * @access public
  638. * @param string $field 字段名
  639. * @param integer $step 增长值
  640. * @return boolean
  641. */
  642. public function setInc($field,$step=1) {
  643. return $this->setField($field,array("exp",$field."+".$step));
  644. }
  645. /**
  646. * 字段值减少
  647. * @access public
  648. * @param string $field 字段名
  649. * @param integer $step 减少值
  650. * @return boolean
  651. */
  652. public function setDec($field,$step=1) {
  653. return $this->setField($field,array("exp",$field."-".$step));
  654. }
  655. /**
  656. * 获取一条记录的某个字段值
  657. * @access public
  658. * @param string $field 字段名
  659. * @param string $spea 字段数据间隔符号 NULL返回数组
  660. * @return mixed
  661. */
  662. public function getField($field,$sepa=null) {
  663. $options["field"] = $field;
  664. $options = $this->_parseOptions($options);
  665. $field = trim($field);
  666. if(strpos($field,",")) { // 多字段
  667. $options["limit"] = is_numeric($sepa)?$sepa:"";
  668. $resultSet = $this->db->select($options);
  669. if(!empty($resultSet)) {
  670. $_field = explode(",", $field);
  671. $field = array_keys($resultSet[0]);
  672. $key = array_shift($field);
  673. $key2 = array_shift($field);
  674. $cols = array();
  675. $count = count($_field);
  676. foreach ($resultSet as $result){
  677. $name = $result[$key];
  678. if(2==$count) {
  679. $cols[$name] = $result[$key2];
  680. }else{
  681. $cols[$name] = is_string($sepa)?implode($sepa,array_slice($result,1)):$result;
  682. }
  683. }
  684. return $cols;
  685. }
  686. }else{ // 查找一条记录
  687. // 返回数据个数
  688. if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据
  689. $options["limit"] = is_numeric($sepa)?$sepa:1;
  690. }
  691. $result = $this->db->select($options);
  692. if(!empty($result)) {
  693. if(true !== $sepa && 1==$options["limit"]) return reset($result[0]);
  694. foreach ($result as $val){
  695. $array[] = $val[$field];
  696. }
  697. return $array;
  698. }
  699. }
  700. return null;
  701. }
  702. /**
  703. * 创建数据对象 但不保存到数据库,数据对象就是指的Model.class.php类中的$data属性
  704. * @access public
  705. * @param mixed $data 创建数据
  706. * @param string $type 状态
  707. * @return mixed
  708. */
  709. public function create($data="",$type="") {
  710. // 如果没有传值默认取POST数据
  711. if(empty($data)) {
  712. $data = $_POST;//自动获取$_POST过来的表单数据
  713. }elseif(is_object($data)){
  714. $data = get_object_vars($data);
  715. }
  716. // 验证数据
  717. if(empty($data) || !is_array($data)) {
  718. $this->error = L("_DATA_TYPE_INVALID_");
  719. return false;
  720. }
  721. // 检查字段映射
  722. $data = $this->parseFieldsMap($data,0);//参数2:0-写入 1-读取
  723. // 状态:1-插入模型数据
  724. $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT);
  725. // 检测提交字段的合法性,适用于$this->field("field1,field2...")->create()情况
  726. if(isset($this->options["field"])) { // $this->field("field1,field2...")->create()
  727. $fields = $this->options["field"];
  728. unset($this->options["field"]);
  729. }elseif($type == self::MODEL_INSERT && isset($this->insert_fields)) {
  730. $fields = $this->insert_fields;
  731. }elseif($type == self::MODEL_UPDATE && isset($this->update_fields)) {
  732. $fields = $this->update_fields;
  733. }
  734. if(isset($fields)) {//都是filed()方法中指定的字段
  735. if(is_string($fields)) {
  736. $fields = explode(",",$fields);
  737. }
  738. foreach ($data as $key=>$val){
  739. if(!in_array($key,$fields)) {
  740. unset($data[$key]);
  741. }
  742. }
  743. }
  744. // 数据自动验证
  745. if(!$this->autoValidation($data,$type)) return false;
  746. // 表单令牌验证
  747. if(C("TOKEN_ON") && !$this->autoCheckToken($data)) {
  748. $this->error = L("_TOKEN_ERROR_");
  749. return false;
  750. }
  751. // 验证完成生成数据对象
  752. if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据
  753. $fields = $this->getDbFields();//获取数据表所有字段名
  754. foreach ($data as $key=>$val){//提交过来的表单数据名必须在数据表中存在相同的字段名
  755. if(!in_array($key,$fields)) {
  756. unset($data[$key]);
  757. }elseif(MAGIC_QUOTES_GPC && is_string($val)){
  758. $data[$key] = stripslashes($val);//对提交的标题数据进行过滤处理
  759. }
  760. }
  761. }
  762. // 创建完成对数据进行自动处理
  763. $this->autoOperation($data,$type);//返回$data
  764. // 赋值当前数据对象
  765. $this->data = $data;//将提交过来的表单数据赋值给当前的data属性
  766. // 返回创建的数据以供其他调用
  767. return $data;//返回提交过来的表单数据
  768. }
  769. // 自动表单令牌验证
  770. // TODO ajax无刷新多次提交暂不能满足
  771. public function autoCheckToken($data) {
  772. if(C("TOKEN_ON")){
  773. $name = C("TOKEN_NAME");
  774. if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效
  775. return false;
  776. }
  777. // 令牌验证
  778. list($key,$value) = explode("_",$data[$name]);
  779. if($_SESSION[$name][$key] == $value) { // 防止重复提交
  780. unset($_SESSION[$name][$key]); // 验证完成销毁session
  781. return true;
  782. }
  783. // 开启TOKEN重置
  784. if(C("TOKEN_RESET")) unset($_SESSION[$name][$key]);
  785. return false;
  786. }
  787. return true;
  788. }
  789. /**
  790. * 使用正则验证数据
  791. * @access public
  792. * @param string $value 要验证的数据
  793. * @param string $rule 验证规则
  794. * @return boolean
  795. */
  796. public function regex($value,$rule) {
  797. $validate = array(
  798. "require" => "/.+/",
  799. "email" => "/^w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$/",
  800. "url" => "/^http(s?)://(?:[A-za-z0-9-]+.)+[A-za-z]{2,4}(?:[/?#][/=?%-&~`@[]":+!#w]*)?$/",
  801. "currency" => "/^d+(.d+)?$/",
  802. "number" => "/^d+$/",
  803. "zip" => "/^d{6}$/",
  804. "integer" => "/^[-+]?d+$/",
  805. "double" => "/^[-+]?d+(.d+)?$/",
  806. "english" => "/^[A-Za-z]+$/",
  807. );
  808. // 检查是否有内置的正则表达式
  809. if(isset($validate[strtolower($rule)]))
  810. $rule = $validate[strtolower($rule)];
  811. return preg_match($rule,$value)===1;
  812. }
  813. /**
  814. * 自动表单处理
  815. * @access public
  816. * @param array $data 创建数据
  817. * @param string $type 创建类型
  818. * @return mixed
  819. */
  820. private function autoOperation(&$data,$type) {
  821. if(!empty($this->options["auto"])) {//默认为空
  822. $_auto = $this->options["auto"];
  823. unset($this->options["auto"]);
  824. }elseif(!empty($this->_auto)){//默认为空
  825. $_auto = $this->_auto;
  826. }
  827. // 自动填充
  828. if(isset($_auto)) {
  829. foreach ($_auto as $auto){
  830. // 填充因子定义格式
  831. // array("field","填充内容","填充条件","附加规则",[额外参数])
  832. if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // 默认为新增的时候自动填充
  833. if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) {
  834. switch(trim($auto[3])) {
  835. case "function": // 使用函数进行填充 字段的值作为参数
  836. case "callback": // 使用回调方法
  837. $args = isset($auto[4])?(array)$auto[4]:array();
  838. if(isset($data[$auto[0]])) {
  839. array_unshift($args,$data[$auto[0]]);
  840. }
  841. if("function"==$auto[3]) {
  842. $data[$auto[0]] = call_user_func_array($auto[1], $args);
  843. }else{
  844. $data[$auto[0]] = call_user_func_array(array(&$this,$auto[1]), $args);
  845. }
  846. break;
  847. case "field": // 用其它字段的值进行填充
  848. $data[$auto[0]] = $data[$auto[1]];
  849. break;
  850. case "string":
  851. default: // 默认作为字符串填充
  852. $data[$auto[0]] = $auto[1];
  853. }
  854. if(false === $data[$auto[0]] ) unset($data[$auto[0]]);
  855. }
  856. }
  857. }
  858. return $data;//返回$data
  859. }
  860. /**
  861. * 自动表单验证
  862. * @access protected
  863. * @param array $data 创建数据
  864. * @param string $type 创建类型
  865. * @return boolean
  866. */
  867. protected function autoValidation($data,$type) {
  868. if(!empty($this->options["validate"])) {
  869. $_validate = $this->options["validate"];
  870. unset($this->options["validate"]);
  871. }elseif(!empty($this->_validate)){
  872. $_validate = $this->_validate;
  873. }
  874. // 属性验证
  875. if(isset($_validate)) { // 如果设置了数据自动验证则进行数据验证
  876. if($this->patchValidate) { // 重置验证错误信息
  877. $this->error = array();
  878. }
  879. foreach($_validate as $key=>$val) {
  880. // 验证因子定义格式
  881. // array(field,rule,message,condition,type,when,params)
  882. // 判断是否需要执行验证
  883. if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) {
  884. if(0==strpos($val[2],"{%") && strpos($val[2],"}"))
  885. // 支持提示信息的多语言 使用 {%语言定义} 方式
  886. $val[2] = L(substr($val[2],2,-1));
  887. $val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE;
  888. $val[4] = isset($val[4])?$val[4]:"regex";
  889. // 判断验证条件
  890. switch($val[3]) {
  891. case self::MUST_VALIDATE: // 必须验证 不管表单是否有设置该字段
  892. if(false === $this->_validationField($data,$val))
  893. return false;
  894. break;
  895. case self::VALUE_VALIDATE: // 值不为空的时候才验证
  896. if("" != trim($data[$val[0]]))
  897. if(false === $this->_validationField($data,$val))
  898. return false;
  899. break;
  900. default: // 默认表单存在该字段就验证
  901. if(isset($data[$val[0]]))
  902. if(false === $this->_validationField($data,$val))
  903. return false;
  904. }
  905. }
  906. }
  907. // 批量验证的时候最后返回错误
  908. if(!empty($this->error)) return false;
  909. }
  910. return true;
  911. }
  912. /**
  913. * 验证表单字段 支持批量验证
  914. * 如果批量验证返回错误的数组信息
  915. * @access protected
  916. * @param array $data 创建数据
  917. * @param array $val 验证因子
  918. * @return boolean
  919. */
  920. protected function _validationField($data,$val) {
  921. if(false === $this->_validationFieldItem($data,$val)){
  922. if($this->patchValidate) {
  923. $this->error[$val[0]] = $val[2];
  924. }else{
  925. $this->error = $val[2];
  926. return false;
  927. }
  928. }
  929. return ;
  930. }
  931. /**
  932. * 根据验证因子验证字段
  933. * @access protected
  934. * @param array $data 创建数据
  935. * @param array $val 验证因子
  936. * @return boolean
  937. */
  938. protected function _validationFieldItem($data,$val) {
  939. switch(strtolower(trim($val[4]))) {
  940. case "function":// 使用函数进行验证
  941. case "callback":// 调用方法进行验证
  942. $args = isset($val[6])?(array)$val[6]:array();
  943. if(is_string($val[0]) && strpos($val[0], ","))
  944. $val[0] = explode(",", $val[0]);
  945. if(is_array($val[0])){
  946. // 支持多个字段验证
  947. foreach($val[0] as $field)
  948. $_data[$field] = $data[$field];
  949. array_unshift($args, $_data);
  950. }else{
  951. array_unshift($args, $data[$val[0]]);
  952. }
  953. if("function"==$val[4]) {
  954. return call_user_func_array($val[1], $args);
  955. }else{
  956. return call_user_func_array(array(&$this, $val[1]), $args);
  957. }
  958. case "confirm": // 验证两个字段是否相同
  959. return $data[$val[0]] == $data[$val[1]];
  960. case "unique": // 验证某个值是否唯一
  961. if(is_string($val[0]) && strpos($val[0],","))
  962. $val[0] = explode(",",$val[0]);
  963. $map = array();
  964. if(is_array($val[0])) {
  965. // 支持多个字段验证
  966. foreach ($val[0] as $field)
  967. $map[$field] = $data[$field];
  968. }else{
  969. $map[$val[0]] = $data[$val[0]];
  970. }
  971. if(!empty($data[$this->getPk()])) { // 完善编辑的时候验证唯一
  972. $map[$this->getPk()] = array("neq",$data[$this->getPk()]);
  973. }
  974. if($this->where($map)->find()) return false;
  975. return true;
  976. default: // 检查附加规则
  977. return $this->check($data[$val[0]],$val[1],$val[4]);
  978. }
  979. }
  980. /**
  981. * 验证数据 支持 in between equal length regex expire ip_allow ip_deny
  982. * @access public
  983. * @param string $value 验证数据
  984. * @param mixed $rule 验证表达式
  985. * @param string $type 验证方式 默认为正则验证
  986. * @return boolean
  987. */
  988. public function check($value,$rule,$type="regex"){
  989. switch(strtolower(trim($type))) {
  990. case "in": // 验证是否在某个指定范围之内 逗号分隔字符串或者数组
  991. $range = is_array($rule)?$rule:explode(",",$rule);
  992. return in_array($value ,$range);
  993. case "between": // 验证是否在某个范围
  994. if (is_array($rule)){
  995. $min = $rule[0];
  996. $max = $rule[1];
  997. }else{
  998. list($min,$max) = explode(",",$rule);
  999. }
  1000. return $value>=$min && $value<=$max;
  1001. case "equal": // 验证是否等于某个值
  1002. return $value == $rule;
  1003. case "length": // 验证长度
  1004. $length = mb_strlen($value,"utf-8"); // 当前数据长度
  1005. if(strpos($rule,",")) { // 长度区间
  1006. list($min,$max) = explode(",",$rule);
  1007. return $length >= $min && $length <= $max;
  1008. }else{// 指定长度
  1009. return $length == $rule;
  1010. }
  1011. case "expire":
  1012. list($start,$end) = explode(",",$rule);
  1013. if(!is_numeric($start)) $start = strtotime($start);
  1014. if(!is_numeric($end)) $end = strtotime($end);
  1015. return $_SERVER["REQUEST_TIME"] >= $start && $_SERVER["REQUEST_TIME"] <= $end;
  1016. case "ip_allow": // IP 操作许可验证
  1017. return in_array(get_client_ip(),explode(",",$rule));
  1018. case "ip_deny": // IP 操作禁止验证
  1019. return !in_array(get_client_ip(),explode(",",$rule));
  1020. case "regex":
  1021. default: // 默认使用正则验证 可以使用验证类中定义的验证名称
  1022. // 检查附加规则
  1023. return $this->regex($value,$rule);
  1024. }
  1025. }
  1026. /**
  1027. * SQL查询
  1028. * @access public
  1029. * @param string $sql SQL指令
  1030. * @param mixed $parse 是否需要解析SQL
  1031. * @return mixed
  1032. */
  1033. public function query($sql,$parse=false) {
  1034. if(!is_bool($parse) && !is_array($parse)) {
  1035. $parse = func_get_args();
  1036. array_shift($parse);
  1037. }
  1038. $sql = $this->parseSql($sql,$parse);
  1039. return $this->db->query($sql);
  1040. }
  1041. /**
  1042. * 执行SQL语句
  1043. * @access public
  1044. * @param string $sql SQL指令
  1045. * @param mixed $parse 是否需要解析SQL
  1046. * @return false | integer
  1047. */
  1048. public function execute($sql,$parse=false) {
  1049. if(!is_bool($parse) && !is_array($parse)) {
  1050. $parse = func_get_args();
  1051. array_shift($parse);
  1052. }
  1053. $sql = $this->parseSql($sql,$parse);
  1054. return $this->db->execute($sql);
  1055. }
  1056. /**
  1057. * 解析SQL语句
  1058. * @access public
  1059. * @param string $sql SQL指令
  1060. * @param boolean $parse 是否需要解析SQL
  1061. * @return string
  1062. */
  1063. protected function parseSql($sql,$parse) {
  1064. // 分析表达式
  1065. if(true === $parse) {
  1066. $options = $this->_parseOptions();
  1067. $sql = $this->db->parseSql($sql,$options);
  1068. }elseif(is_array($parse)){ // SQL预处理
  1069. $sql = vsprintf($sql,$parse);
  1070. }else{
  1071. if(strpos($sql,"__TABLE__"))
  1072. $sql = str_replace("__TABLE__",$this->getTableName(),$sql);
  1073. }
  1074. $this->db->setModel($this->name);
  1075. return $sql;
  1076. }
  1077. /**
  1078. * 切换当前的数据库连接
  1079. * @access public
  1080. * @param integer $linkNum 连接序号
  1081. * @param mixed $config 数据库连接信息
  1082. * @param array $params 模型参数
  1083. * @return Model
  1084. */
  1085. public function db($linkNum="",$config="",$params=array()){
  1086. if(""===$linkNum && $this->db) {//如果当前数据库操作对象存在,则直接返回当前数据库操作对象
  1087. return $this->db;//当前数据库操作对象
  1088. }
  1089. static $_linkNum = array();//连接序号
  1090. static $_db = array();
  1091. //默认执行if
  1092. if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $config && $_linkNum[$linkNum]!=$config) ) {
  1093. // 创建一个新的实例,默认不执行
  1094. if(!empty($config) && is_string($config) && false === strpos($config,"/")) { // 支持读取配置参数
  1095. //默认不执行
  1096. $config = C($config);
  1097. }
  1098. //默认执行,返回一个数据库驱动类Db,class.php实例化对象
  1099. /**
  1100. * Db::getInstance($config);详解
  1101. * 第一步:查找Db.class.php类库的getInstance()方法
  1102. * 第二步:getInstance()方法调用common.php文件的get_instance_of(__CLASS__,"factory",$args);
  1103. * 第三步:get_instance_of(__CLASS__,"factory",$args)再次调用Db.class.php类的factory()方法
  1104. * 第四步:Db.class.php中的factory()方法,会加载数据库驱动类文件DbMysql.class.php,并返回一个数据库驱动类实例化对象
  1105. */
  1106. $_db[$linkNum] = Db::getInstance($config);//返回一个数据库驱动类DbMysql.class.php实例化对象
  1107. }elseif(NULL === $config){
  1108. $_db[$linkNum]->close(); // 关闭数据库连接
  1109. unset($_db[$linkNum]);
  1110. return ;
  1111. }
  1112. if(!empty($params)) {//默认不执行
  1113. if(is_string($params)) parse_str($params,$params);
  1114. foreach ($params as $name=>$value){
  1115. $this->setProperty($name,$value);
  1116. }
  1117. }
  1118. // 记录连接信息
  1119. $_linkNum[$linkNum] = $config;
  1120. // 切换数据库连接
  1121. $this->db = $_db[$linkNum];//数据库驱动类Db,class.php实例化对象
  1122. $this->_after_db();
  1123. // 字段检测 是否自动检测数据表字段信息
  1124. if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo();
  1125. return $this;//返回当前对象,其中就包括数据库连接对象
  1126. }
  1127. // 数据库切换后回调方法
  1128. protected function _after_db() {}
  1129. /**
  1130. * 得到当前的数据对象名称
  1131. * @access public
  1132. * @return string
  1133. */
  1134. public function getModelName() {
  1135. if(empty($this->name))
  1136. $this->name = substr(get_class($this),0,-5);
  1137. return $this->name;
  1138. }
  1139. /**
  1140. * 得到完整的数据表名
  1141. * @access public
  1142. * @return string
  1143. */
  1144. public function getTableName() {
  1145. if(empty($this->trueTableName)) {
  1146. $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : "";//think_
  1147. if(!empty($this->tableName)) {//默认不执行
  1148. $tableName .= $this->tableName;
  1149. }else{
  1150. //parse_name()函数将模型名转化为小写,如,User转换为user
  1151. //think_user
  1152. $tableName .= parse_name($this->name);
  1153. }
  1154. //真实表名
  1155. $this->trueTableName = strtolower($tableName);
  1156. }
  1157. //think_user
  1158. return (!empty($this->dbName)?$this->dbName.".":"").$this->trueTableName;
  1159. }
  1160. /**
  1161. * 启动事务
  1162. * @access public
  1163. * @return void
  1164. */
  1165. public function startTrans() {
  1166. $this->commit();
  1167. $this->db->startTrans();
  1168. return ;
  1169. }
  1170. /**
  1171. * 提交事务
  1172. * @access public
  1173. * @return boolean
  1174. */
  1175. public function commit() {
  1176. return $this->db->commit();
  1177. }
  1178. /**
  1179. * 事务回滚
  1180. * @access public
  1181. * @return boolean
  1182. */
  1183. public function rollback() {
  1184. return $this->db->rollback();
  1185. }
  1186. /**
  1187. * 返回模型的错误信息
  1188. * @access public
  1189. * @return string
  1190. */
  1191. public function getError(){
  1192. return $this->error;
  1193. }
  1194. /**
  1195. * 返回数据库的错误信息
  1196. * @access public
  1197. * @return string
  1198. */
  1199. public function getDbError() {
  1200. return $this->db->getError();
  1201. }
  1202. /**
  1203. * 返回最后插入的ID
  1204. * @access public
  1205. * @return string
  1206. */
  1207. public function getLastInsID() {
  1208. return $this->db->getLastInsID();
  1209. }
  1210. /**
  1211. * 返回最后执行的sql语句
  1212. * @access public
  1213. * @return string
  1214. */
  1215. public function getLastSql() {
  1216. return $this->db->getLastSql($this->name);
  1217. }
  1218. // 鉴于getLastSql比较常用 增加_sql 别名
  1219. public function _sql(){
  1220. return $this->getLastSql();
  1221. }
  1222. /**
  1223. * 获取主键名称
  1224. * @access public
  1225. * @return string
  1226. */
  1227. public function getPk() {
  1228. return isset($this->fields["_pk"])?$this->fields["_pk"]:$this->pk;
  1229. }
  1230. /**
  1231. * 获取数据表字段信息
  1232. * @access public
  1233. * @return array
  1234. */
  1235. public function getDbFields(){
  1236. if(isset($this->options["table"])) {// 动态指定表名
  1237. $fields = $this->db->getFields($this->options["table"]);
  1238. return $fields?array_keys($fields):false;
  1239. }
  1240. if($this->fields) {
  1241. $fields = $this->fields;
  1242. unset($fields["_autoinc"],$fields["_pk"],$fields["_type"],$fields["_version"]);
  1243. return $fields;
  1244. }
  1245. return false;
  1246. }
  1247. /**
  1248. * 设置数据对象值
  1249. * @access public
  1250. * @param mixed $data 数据
  1251. * @return Model
  1252. */
  1253. public function data($data=""){
  1254. if("" === $data && !empty($this->data)) {
  1255. return $this->data;
  1256. }
  1257. if(is_object($data)){
  1258. $data = get_object_vars($data);
  1259. }elseif(is_string($data)){
  1260. parse_str($data,$data);
  1261. }elseif(!is_array($data)){
  1262. throw_exception(L("_DATA_TYPE_INVALID_"));
  1263. }
  1264. $this->data = $data;
  1265. return $this;
  1266. }
  1267. /**
  1268. * 查询SQL组装 join
  1269. * @access public
  1270. * @param mixed $join
  1271. * @return Model
  1272. */
  1273. public function join($join) {
  1274. if(is_array($join)) {
  1275. $this->options["join"] = $join;
  1276. }elseif(!empty($join)) {
  1277. $this->options["join"][] = $join;
  1278. }
  1279. return $this;
  1280. }
  1281. /**
  1282. * 查询SQL组装 union
  1283. * @access public
  1284. * @param mixed $union
  1285. * @param boolean $all
  1286. * @return Model
  1287. */
  1288. public function union($union,$all=false) {
  1289. if(empty($union)) return $this;
  1290. if($all) {
  1291. $this->options["union"]["_all"] = true;
  1292. }
  1293. if(is_object($union)) {
  1294. $union = get_object_vars($union);
  1295. }
  1296. // 转换union表达式
  1297. if(is_string($union) ) {
  1298. $options = $union;
  1299. }elseif(is_array($union)){
  1300. if(isset($union[0])) {
  1301. $this->options["union"] = array_merge($this->options["union"],$union);
  1302. return $this;
  1303. }else{
  1304. $options = $union;
  1305. }
  1306. }else{
  1307. throw_exception(L("_DATA_TYPE_INVALID_"));
  1308. }
  1309. $this->options["union"][] = $options;
  1310. return $this;
  1311. }
  1312. /**
  1313. * 查询缓存
  1314. * @access public
  1315. * @param mixed $key
  1316. * @param integer $expire
  1317. * @param string $type
  1318. * @return Model
  1319. */
  1320. public function cache($key=true,$expire=null,$type=""){
  1321. $this->options["cache"] = array("key"=>$key,"expire"=>$expire,"type"=>$type);
  1322. return $this;
  1323. }
  1324. /**
  1325. * 指定查询字段 支持字段排除
  1326. * @access public
  1327. * @param mixed $field
  1328. * @param boolean $except 是否排除
  1329. * @return Model
  1330. */
  1331. public function field($field,$except=false){
  1332. if(true === $field) {// 获取全部字段
  1333. $fields = $this->getDbFields();
  1334. $field = $fields?$fields:"*";
  1335. }elseif($except) {// 字段排除
  1336. if(is_string($field)) {
  1337. $field = explode(",",$field);
  1338. }
  1339. $fields = $this->getDbFields();
  1340. $field = $fields?array_diff($fields,$field):$field;
  1341. }
  1342. $this->options["field"] = $field;
  1343. return $this;
  1344. }
  1345. /**
  1346. * 调用命名范围
  1347. * @access public
  1348. * @param mixed $scope 命名范围名称 支持多个 和直接定义
  1349. * @param array $args 参数
  1350. * @return Model
  1351. */
  1352. public function scope($scope="",$args=NULL){
  1353. if("" === $scope) {
  1354. if(isset($this->_scope["default"])) {
  1355. // 默认的命名范围
  1356. $options = $this->_scope["default"];
  1357. }else{
  1358. return $this;
  1359. }
  1360. }elseif(is_string($scope)){ // 支持多个命名范围调用 用逗号分割
  1361. $scopes = explode(",",$scope);
  1362. $options = array();
  1363. foreach ($scopes as $name){
  1364. if(!isset($this->_scope[$name])) continue;
  1365. $options = array_merge($options,$this->_scope[$name]);
  1366. }
  1367. if(!empty($args) && is_array($args)) {
  1368. $options = array_merge($options,$args);
  1369. }
  1370. }elseif(is_array($scope)){ // 直接传入命名范围定义
  1371. $options = $scope;
  1372. }
  1373. if(is_array($options) && !empty($options)){
  1374. $this->options = array_merge($this->options,array_change_key_case($options));
  1375. }
  1376. return $this;
  1377. }
  1378. /**
  1379. * 指定查询条件 支持安全过滤
  1380. * @access public
  1381. * @param mixed $where 条件表达式
  1382. * @param mixed $parse 预处理参数
  1383. * @return Model
  1384. */
  1385. public function where($where,$parse=null){
  1386. if(!is_null($parse) && is_string($where)) {
  1387. if(!is_array($parse)) {
  1388. $parse = func_get_args();
  1389. array_shift($parse);
  1390. }
  1391. $parse = array_map(array($this->db,"escapeString"),$parse);
  1392. $where = vsprintf($where,$parse);
  1393. }elseif(is_object($where)){
  1394. $where = get_object_vars($where);
  1395. }
  1396. $this->options["where"] = $where;
  1397. return $this;
  1398. }
  1399. /**
  1400. * 指定查询数量
  1401. * @access public
  1402. * @param mixed $offset 起始位置
  1403. * @param mixed $length 查询数量
  1404. * @return Model
  1405. */
  1406. public function limit($offset,$length=null){
  1407. $this->options["limit"] = is_null($length)?$offset:$offset.",".$length;
  1408. return $this;
  1409. }
  1410. /**
  1411. * 指定分页
  1412. * @access public
  1413. * @param mixed $page 页数
  1414. * @param mixed $listRows 每页数量
  1415. * @return Model
  1416. */
  1417. public function page($page,$listRows=null){
  1418. $this->options["page"] = is_null($listRows)?$page:$page.",".$listRows;
  1419. return $this;
  1420. }
  1421. /**
  1422. * 设置模型的属性值
  1423. * @access public
  1424. * @param string $name 名称
  1425. * @param mixed $value 值
  1426. * @return Model
  1427. */
  1428. public function setProperty($name,$value) {
  1429. if(property_exists($this,$name))
  1430. $this->$name = $value;
  1431. return $this;
  1432. }
  1433. }?>

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21414.html

相关文章

  • [系统安全] 三十五.Procmon工具基本用法及文件进程、注册表查看

    摘要:本文将分享软件基本用法及文件进程注册表查看,这是一款微软推荐的系统监视工具,功能非常强大可用来检测恶意软件。可以帮助使用者对系统中的任何文件注册表操作进行监视和记录,通过注册表和文件读写的变化,有效帮助诊断系统故障或发现恶意软件病毒及木马。 ...

    kk_miles 评论0 收藏0
  • PHP 性能分析第一篇: Xhprof & Xhgui 介绍

    摘要:注这是我们应用性能分析系列的第一篇,阅读第二篇可深入了解,第三篇则关注于性能调优实践。性能分析的行为也会影响应用性能。主动被动性能分析主动分析器在开发过程中使用,由开发人员启用。它对性能的影响最小,同时收集足够的信息用于诊断性能问题。 注:这是我们 PHP 应用性能分析系列的第一篇,阅读第二篇可深入了解 xhgui,第三篇则关注于性能调优实践。 什么是性能分析? 性能分析是衡量应用程...

    RdouTyping 评论0 收藏0
  • 简杰的php编程分享-1.3 xdebug性能分析

    摘要:生成性能分析文件,再通过分析软件进行查看性能结果。性能分析工具详解我们通过打开性能分析文件打头的文件。可以很好的区分性能分析文件。 介绍 在上两期中我已经对 xdebug 最核心的操作已经进行了讲解。相信你可以摆脱写 var_dump($data);die; 的编写和完成调试后的清除了。这一期我们来学习xdebug的第二个特色-性能分析。这一个功能,在实操中用的不是很多。 使用场景: ...

    Michael_Lin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<