Model.class.php 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  1. <?php
  2. // +--------------------------------------------------------------------------
  3. // | Senthot [ DEVELOPED BY ME ]
  4. // +--------------------------------------------------------------------------
  5. // | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
  6. // | License ( http://www.apache.org/licenses/LICENSE-2.0 )
  7. // | Author: ms134n ( [email protected] )
  8. // +--------------------------------------------------------------------------
  9. /**
  10. * Senthot Model class that
  11. * ORM and realized ActiveRecords mode
  12. * @category Sen
  13. * @package Sen
  14. * @subpackage Core
  15. * @author ms134n <[email protected]>
  16. */
  17. class Model {
  18. // Operation Status
  19. const MODEL_INSERT = 1; // Insert model data
  20. const MODEL_UPDATE = 2; // Updating model data
  21. const MODEL_BOTH = 3; // Contains the above two methods
  22. const MUST_VALIDATE = 1;// Must verify
  23. const EXISTS_VALIDATE = 0;// There is a form field validation
  24. const VALUE_VALIDATE = 2;// Not empty form value validation
  25. // Addonsed model currently in use
  26. private $_extModel = null;
  27. // Current object database operations
  28. protected $db = null;
  29. // Primary key name
  30. protected $pk = 'id';
  31. // Table Prefix
  32. protected $tablePrefix = '';
  33. // Model Name
  34. protected $name = '';
  35. // Database Name
  36. protected $dbName = '';
  37. //Database configuration
  38. protected $connection = '';
  39. // Data table name ( does not contain a table prefix )
  40. protected $tableName = '';
  41. // Actual data table name ( including table prefix )
  42. protected $trueTableName = '';
  43. // Recent error message
  44. protected $error = '';
  45. // Field Information
  46. protected $fields = array();
  47. // Data information
  48. protected $data = array();
  49. // Query expression parameter
  50. protected $options = array();
  51. protected $_validate = array(); // Automatic verification Definition
  52. protected $_auto = array(); // Auto-complete definitions
  53. protected $_map = array(); // Field mapping definition
  54. protected $_scope = array(); // Named range definition
  55. // Whether to automatically detect the data table field information
  56. protected $autoCheckFields = true;
  57. // Whether batch verification
  58. protected $patchValidate = false;
  59. // Chain operation method list
  60. protected $methods = array('table','order','alias','having','group','lock','distinct','auto','filter','validate');
  61. /**
  62. * Architecture function
  63. * Obtain DB class instance object Field inspection
  64. * @access public
  65. * @param string $name Model Name
  66. * @param string $tablePrefix Table Prefix
  67. * @param mixed $connection Database connection information
  68. */
  69. public function __construct($name='',$tablePrefix='',$connection='') {
  70. // Model initialization
  71. $this->_initialize();
  72. // Get the model name
  73. if(!empty($name)) {
  74. if(strpos($name,'.')) { // Support Database name. Model name Definition
  75. list($this->dbName,$this->name) = explode('.',$name);
  76. }else{
  77. $this->name = $name;
  78. }
  79. }elseif(empty($this->name)){
  80. $this->name = $this->getModelName();
  81. }
  82. // Set Table Prefix
  83. if(is_null($tablePrefix)) {// Null means no prefix prefix
  84. $this->tablePrefix = '';
  85. }elseif('' != $tablePrefix) {
  86. $this->tablePrefix = $tablePrefix;
  87. }else{
  88. $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX');
  89. }
  90. // Database initialization
  91. // Gets an object database operations
  92. // Current model has a separate database connection information
  93. $this->db(0,empty($this->connection)?$connection:$this->connection);
  94. }
  95. /**
  96. * Automatic detection of data table information
  97. * @access protected
  98. * @return void
  99. */
  100. protected function _checkTableInfo() {
  101. // If not Model class Automatically record the data table information
  102. // Only the first execution record
  103. if(empty($this->fields)) {
  104. // If the data table field is not defined is automatically acquired
  105. if(C('DB_FIELDS_CACHE')) {
  106. $db = $this->dbName?$this->dbName:C('DB_NAME');
  107. $fields = F('_fields/'.strtolower($db.'.'.$this->name));
  108. if($fields) {
  109. $version = C('DB_FIELD_VERISON');
  110. if(empty($version) || $fields['_version']== $version) {
  111. $this->fields = $fields;
  112. return ;
  113. }
  114. }
  115. }
  116. // Read data every time table information
  117. $this->flush();
  118. }
  119. }
  120. /**
  121. * Get field information and cache
  122. * @access public
  123. * @return void
  124. */
  125. public function flush() {
  126. // Cache does not exist query data table information
  127. $this->db->setModel($this->name);
  128. $fields = $this->db->getFields($this->getTableName());
  129. if(!$fields) { // Unable to get field information
  130. return false;
  131. }
  132. $this->fields = array_keys($fields);
  133. $this->fields['_autoinc'] = false;
  134. foreach ($fields as $key=>$val){
  135. // Record Field Type
  136. $type[$key] = $val['type'];
  137. if($val['primary']) {
  138. $this->fields['_pk'] = $key;
  139. if($val['autoinc']) $this->fields['_autoinc'] = true;
  140. }
  141. }
  142. // Record field type information
  143. $this->fields['_type'] = $type;
  144. if(C('DB_FIELD_VERISON')) $this->fields['_version'] = C('DB_FIELD_VERISON');
  145. // 2008-3-7 Increase the cache switch control
  146. if(C('DB_FIELDS_CACHE')){
  147. // Persistent cache data sheet information
  148. $db = $this->dbName?$this->dbName:C('DB_NAME');
  149. F('_fields/'.strtolower($db.'.'.$this->name),$this->fields);
  150. }
  151. }
  152. /**
  153. * Dynamic switching extended model
  154. * @access public
  155. * @param string $type Model type name
  156. * @param mixed $vars To addons the model attribute variables passed
  157. * @return Model
  158. */
  159. public function switchModel($type,$vars=array()) {
  160. $class = ucwords(strtolower($type)).'Model';
  161. if(!class_exists($class))
  162. throw_exception($class.L('_MODEL_NOT_EXIST_'));
  163. // Addonsed model instantiation
  164. $this->_extModel = new $class($this->name);
  165. if(!empty($vars)) {
  166. // Incoming current model to addons the model attributes
  167. foreach ($vars as $var)
  168. $this->_extModel->setProperty($var,$this->$var);
  169. }
  170. return $this->_extModel;
  171. }
  172. /**
  173. * Set the value of the data object
  174. * @access public
  175. * @param string $name Name
  176. * @param mixed $value Value
  177. * @return void
  178. */
  179. public function __set($name,$value) {
  180. // Setting Data object properties
  181. $this->data[$name] = $value;
  182. }
  183. /**
  184. * Gets the value of the data object
  185. * @access public
  186. * @param string $name Name
  187. * @return mixed
  188. */
  189. public function __get($name) {
  190. return isset($this->data[$name])?$this->data[$name]:null;
  191. }
  192. /**
  193. * Detecting the value of the data object
  194. * @access public
  195. * @param string $name Name
  196. * @return boolean
  197. */
  198. public function __isset($name) {
  199. return isset($this->data[$name]);
  200. }
  201. /**
  202. * Destroy the value of the data object
  203. * @access public
  204. * @param string $name Name
  205. * @return void
  206. */
  207. public function __unset($name) {
  208. unset($this->data[$name]);
  209. }
  210. /**
  211. * Use __call method to achieve some special Model Method
  212. * @access public
  213. * @param string $method Method name
  214. * @param array $args Call parameters
  215. * @return mixed
  216. */
  217. public function __call($method,$args) {
  218. if(in_array(strtolower($method),$this->methods,true)) {
  219. // Coherent implementation of the operation
  220. $this->options[strtolower($method)] = $args[0];
  221. return $this;
  222. }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){
  223. // Achieve statistical inquiry
  224. $field = isset($args[0])?$args[0]:'*';
  225. return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method);
  226. }elseif(strtolower(substr($method,0,5))=='getby') {
  227. // According to a field to obtain records
  228. $field = parse_name(substr($method,5));
  229. $where[$field] = $args[0];
  230. return $this->where($where)->find();
  231. }elseif(strtolower(substr($method,0,10))=='getfieldby') {
  232. // According to a field to a value obtained records
  233. $name = parse_name(substr($method,10));
  234. $where[$name] =$args[0];
  235. return $this->where($where)->getField($args[1]);
  236. }elseif(isset($this->_scope[$method])){// Individual named range called Support
  237. return $this->scope($method,$args[0]);
  238. }else{
  239. throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
  240. return;
  241. }
  242. }
  243. // Callback method Initialize model
  244. protected function _initialize() {}
  245. /**
  246. * The data saved to the database for processing
  247. * @access protected
  248. * @param mixed $data The data to be operated
  249. * @return boolean
  250. */
  251. protected function _facade($data) {
  252. // Check the non-data fields
  253. if(!empty($this->fields)) {
  254. foreach ($data as $key=>$val){
  255. if(!in_array($key,$this->fields,true)){
  256. unset($data[$key]);
  257. }elseif(is_scalar($val)) {
  258. // Field type checking
  259. $this->_parseType($data,$key);
  260. }
  261. }
  262. }
  263. // Security filtering
  264. if(!empty($this->options['filter'])) {
  265. $data = array_map($this->options['filter'],$data);
  266. unset($this->options['filter']);
  267. }
  268. $this->_before_write($data);
  269. return $data;
  270. }
  271. // Callback method before writing data Including new and updated
  272. protected function _before_write(&$data) {}
  273. /**
  274. * Added Data
  275. * @access public
  276. * @param mixed $data Data
  277. * @param array $options Expression
  278. * @param boolean $replace Whether or replace
  279. * @return mixed
  280. */
  281. public function add($data='',$options=array(),$replace=false) {
  282. if(empty($data)) {
  283. // No transmission of data , access to the current value of the data object
  284. if(!empty($this->data)) {
  285. $data = $this->data;
  286. // Reset Data
  287. $this->data = array();
  288. }else{
  289. $this->error = L('_DATA_TYPE_INVALID_');
  290. return false;
  291. }
  292. }
  293. // Analysis Expressions
  294. $options = $this->_parseOptions($options);
  295. // Data Processing
  296. $data = $this->_facade($data);
  297. if(false === $this->_before_insert($data,$options)) {
  298. return false;
  299. }
  300. // Write data to the database
  301. $result = $this->db->insert($data,$options,$replace);
  302. if(false !== $result ) {
  303. $insertId = $this->getLastInsID();
  304. if($insertId) {
  305. // Increment primary key to return to insert ID
  306. $data[$this->getPk()] = $insertId;
  307. $this->_after_insert($data,$options);
  308. return $insertId;
  309. }
  310. $this->_after_insert($data,$options);
  311. }
  312. return $result;
  313. }
  314. // Callback method before inserting data
  315. protected function _before_insert(&$data,$options) {}
  316. // Inserted after the success callback method
  317. protected function _after_insert($data,$options) {}
  318. public function addAll($dataList,$options=array(),$replace=false){
  319. if(empty($dataList)) {
  320. $this->error = L('_DATA_TYPE_INVALID_');
  321. return false;
  322. }
  323. // Analysis Expressions
  324. $options = $this->_parseOptions($options);
  325. // Data Processing
  326. foreach ($dataList as $key=>$data){
  327. $dataList[$key] = $this->_facade($data);
  328. }
  329. // Write data to the database
  330. $result = $this->db->insertAll($dataList,$options,$replace);
  331. if(false !== $result ) {
  332. $insertId = $this->getLastInsID();
  333. if($insertId) {
  334. return $insertId;
  335. }
  336. }
  337. return $result;
  338. }
  339. /**
  340. * Added through Select records
  341. * @access public
  342. * @param string $fields To insert a data table field names
  343. * @param string $table To insert the data table name
  344. * @param array $options Expression
  345. * @return boolean
  346. */
  347. public function selectAdd($fields='',$table='',$options=array()) {
  348. // Analysis Expressions
  349. $options = $this->_parseOptions($options);
  350. // Write data to the database
  351. if(false === $result = $this->db->selectInsert($fields?$fields:$options['field'],$table?$table:$this->getTableName(),$options)){
  352. // Database insert operation failed
  353. $this->error = L('_OPERATION_WRONG_');
  354. return false;
  355. }else {
  356. // Successful insertion
  357. return $result;
  358. }
  359. }
  360. /**
  361. * Saving Data
  362. * @access public
  363. * @param mixed $data Data
  364. * @param array $options Expression
  365. * @return boolean
  366. */
  367. public function save($data='',$options=array()) {
  368. if(empty($data)) {
  369. // No transmission of data , access to the current value of the data object
  370. if(!empty($this->data)) {
  371. $data = $this->data;
  372. // Reset Data
  373. $this->data = array();
  374. }else{
  375. $this->error = L('_DATA_TYPE_INVALID_');
  376. return false;
  377. }
  378. }
  379. // Data Processing
  380. $data = $this->_facade($data);
  381. // Analysis Expressions
  382. $options = $this->_parseOptions($options);
  383. if(false === $this->_before_update($data,$options)) {
  384. return false;
  385. }
  386. if(!isset($options['where']) ) {
  387. // If there is a primary key data Is automatically updated as conditions
  388. if(isset($data[$this->getPk()])) {
  389. $pk = $this->getPk();
  390. $where[$pk] = $data[$pk];
  391. $options['where'] = $where;
  392. $pkValue = $data[$pk];
  393. unset($data[$pk]);
  394. }else{
  395. // If there are any updated conditions does
  396. $this->error = L('_OPERATION_WRONG_');
  397. return false;
  398. }
  399. }
  400. $result = $this->db->update($data,$options);
  401. if(false !== $result) {
  402. if(isset($pkValue)) $data[$pk] = $pkValue;
  403. $this->_after_update($data,$options);
  404. }
  405. return $result;
  406. }
  407. // The callback method before the data is updated
  408. protected function _before_update(&$data,$options) {}
  409. // After a successful update callback methods
  410. protected function _after_update($data,$options) {}
  411. /**
  412. * Deleting data
  413. * @access public
  414. * @param mixed $options Expression
  415. * @return mixed
  416. */
  417. public function delete($options=array()) {
  418. if(empty($options) && empty($this->options['where'])) {
  419. // If the deletion criteria is empty Delete object corresponding to the current data record
  420. if(!empty($this->data) && isset($this->data[$this->getPk()]))
  421. return $this->delete($this->data[$this->getPk()]);
  422. else
  423. return false;
  424. }
  425. if(is_numeric($options) || is_string($options)) {
  426. // Based on primary keys deleting records
  427. $pk = $this->getPk();
  428. if(strpos($options,',')) {
  429. $where[$pk] = array('IN', $options);
  430. }else{
  431. $where[$pk] = $options;
  432. }
  433. $pkValue = $where[$pk];
  434. $options = array();
  435. $options['where'] = $where;
  436. }
  437. // Analysis Expressions
  438. $options = $this->_parseOptions($options);
  439. $result= $this->db->delete($options);
  440. if(false !== $result) {
  441. $data = array();
  442. if(isset($pkValue)) $data[$pk] = $pkValue;
  443. $this->_after_delete($data,$options);
  444. }
  445. // Returns the deleted records number
  446. return $result;
  447. }
  448. // Deleted after a successful callback methods
  449. protected function _after_delete($data,$options) {}
  450. /**
  451. * Querying datasets
  452. * @access public
  453. * @param array $options Expression arguments
  454. * @return mixed
  455. */
  456. public function select($options=array()) {
  457. if(is_string($options) || is_numeric($options)) {
  458. // According to the primary key query
  459. $pk = $this->getPk();
  460. if(strpos($options,',')) {
  461. $where[$pk] = array('IN',$options);
  462. }else{
  463. $where[$pk] = $options;
  464. }
  465. $options = array();
  466. $options['where'] = $where;
  467. }elseif(false === $options){ // For subqueries Not only returns SQL
  468. $options = array();
  469. // Analysis Expressions
  470. $options = $this->_parseOptions($options);
  471. return '( '.$this->db->buildSelectSql($options).' )';
  472. }
  473. // Analysis Expressions
  474. $options = $this->_parseOptions($options);
  475. $resultSet = $this->db->select($options);
  476. if(false === $resultSet) {
  477. return false;
  478. }
  479. if(empty($resultSet)) { // Query result is empty
  480. return null;
  481. }
  482. $this->_after_select($resultSet,$options);
  483. return $resultSet;
  484. }
  485. // After a successful query callback methods
  486. protected function _after_select(&$resultSet,$options) {}
  487. /**
  488. * Generate SQL queries Can be used in a subquery
  489. * @access public
  490. * @param array $options Expression arguments
  491. * @return string
  492. */
  493. public function buildSql($options=array()) {
  494. // Analysis Expressions
  495. $options = $this->_parseOptions($options);
  496. return '( '.$this->db->buildSelectSql($options).' )';
  497. }
  498. /**
  499. * Analysis Expressions
  500. * @access proteced
  501. * @param array $options Expression arguments
  502. * @return array
  503. */
  504. protected function _parseOptions($options=array()) {
  505. if(is_array($options))
  506. $options = array_merge($this->options,$options);
  507. // Query after emptying the SQL expression to assemble Avoid the next query
  508. $this->options = array();
  509. if(!isset($options['table'])){
  510. // Automatically get the table name
  511. $options['table'] = $this->getTableName();
  512. $fields = $this->fields;
  513. }else{
  514. // Specifies the data sheet then reacquire the field list but not Support type detection
  515. $fields = $this->getDbFields();
  516. }
  517. if(!empty($options['alias'])) {
  518. $options['table'] .= ' '.$options['alias'];
  519. }
  520. // Recording operation Model Name
  521. $options['model'] = $this->name;
  522. // Field type validation
  523. if(isset($options['where']) && is_array($options['where']) && !empty($fields)) {
  524. // Query the array for the field type checking
  525. foreach ($options['where'] as $key=>$val){
  526. $key = trim($key);
  527. if(in_array($key,$fields,true)){
  528. if(is_scalar($val)) {
  529. $this->_parseType($options['where'],$key);
  530. }
  531. }elseif('_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'|') && false === strpos($key,'&')){
  532. unset($options['where'][$key]);
  533. }
  534. }
  535. }
  536. // Expression Filter
  537. $this->_options_filter($options);
  538. return $options;
  539. }
  540. // Expression Filter callback method
  541. protected function _options_filter(&$options) {}
  542. /**
  543. * Data type detection
  544. * @access protected
  545. * @param mixed $data Data
  546. * @param string $key Field name
  547. * @return void
  548. */
  549. protected function _parseType(&$data,$key) {
  550. $fieldType = strtolower($this->fields['_type'][$key]);
  551. if(false === strpos($fieldType,'bigint') && false !== strpos($fieldType,'int')) {
  552. $data[$key] = intval($data[$key]);
  553. }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){
  554. $data[$key] = floatval($data[$key]);
  555. }elseif(false !== strpos($fieldType,'bool')){
  556. $data[$key] = (bool)$data[$key];
  557. }
  558. }
  559. /**
  560. * Query data
  561. * @access public
  562. * @param mixed $options Expression arguments
  563. * @return mixed
  564. */
  565. public function find($options=array()) {
  566. if(is_numeric($options) || is_string($options)) {
  567. $where[$this->getPk()] = $options;
  568. $options = array();
  569. $options['where'] = $where;
  570. }
  571. // Always find a record
  572. $options['limit'] = 1;
  573. // Analysis Expressions
  574. $options = $this->_parseOptions($options);
  575. $resultSet = $this->db->select($options);
  576. if(false === $resultSet) {
  577. return false;
  578. }
  579. if(empty($resultSet)) {// Query result is empty
  580. return null;
  581. }
  582. $this->data = $resultSet[0];
  583. $this->_after_find($this->data,$options);
  584. return $this->data;
  585. }
  586. // Query success callback method
  587. protected function _after_find(&$result,$options) {}
  588. /**
  589. * Processing field mapping
  590. * @access public
  591. * @param array $data Current Data
  592. * @param integer $type Type 0 Write 1 Read
  593. * @return array
  594. */
  595. public function parseFieldsMap($data,$type=1) {
  596. // Check the field mapping
  597. if(!empty($this->_map)) {
  598. foreach ($this->_map as $key=>$val){
  599. if($type==1) { // Read
  600. if(isset($data[$val])) {
  601. $data[$key] = $data[$val];
  602. unset($data[$val]);
  603. }
  604. }else{
  605. if(isset($data[$key])) {
  606. $data[$val] = $data[$key];
  607. unset($data[$key]);
  608. }
  609. }
  610. }
  611. }
  612. return $data;
  613. }
  614. /**
  615. * Set the value of a field record
  616. * Support using the database fields and methods
  617. * @access public
  618. * @param string|array $field Field name
  619. * @param string $value Field values
  620. * @return boolean
  621. */
  622. public function setField($field,$value='') {
  623. if(is_array($field)) {
  624. $data = $field;
  625. }else{
  626. $data[$field] = $value;
  627. }
  628. return $this->save($data);
  629. }
  630. /**
  631. * Field Value Growth
  632. * @access public
  633. * @param string $field Field name
  634. * @param integer $step Growth in value
  635. * @return boolean
  636. */
  637. public function setInc($field,$step=1) {
  638. return $this->setField($field,array('exp',$field.'+'.$step));
  639. }
  640. /**
  641. * Field value Decrease
  642. * @access public
  643. * @param string $field Field name
  644. * @param integer $step Decrease the value
  645. * @return boolean
  646. */
  647. public function setDec($field,$step=1) {
  648. return $this->setField($field,array('exp',$field.'-'.$step));
  649. }
  650. /**
  651. * Gets the value of a field in a record
  652. * @access public
  653. * @param string $field Field name
  654. * @param string $spea Field data symbol interval NULL returned array
  655. * @return mixed
  656. */
  657. public function getField($field,$sepa=null) {
  658. $options['field'] = $field;
  659. $options = $this->_parseOptions($options);
  660. $field = trim($field);
  661. if(strpos($field,',')) { // Multi-Field
  662. if(!isset($options['limit'])){
  663. $options['limit'] = is_numeric($sepa)?$sepa:'';
  664. }
  665. $resultSet = $this->db->select($options);
  666. if(!empty($resultSet)) {
  667. $_field = explode(',', $field);
  668. $field = array_keys($resultSet[0]);
  669. $key = array_shift($field);
  670. $key2 = array_shift($field);
  671. $cols = array();
  672. $count = count($_field);
  673. foreach ($resultSet as $result){
  674. $name = $result[$key];
  675. if(2==$count) {
  676. $cols[$name] = $result[$key2];
  677. }else{
  678. $cols[$name] = is_string($sepa)?implode($sepa,$result):$result;
  679. }
  680. }
  681. return $cols;
  682. }
  683. }else{ // Find a record
  684. // Return the number of data
  685. if(true !== $sepa) {// While sepa is specified as true, returns all of the data
  686. $options['limit'] = is_numeric($sepa)?$sepa:1;
  687. }
  688. $result = $this->db->select($options);
  689. if(!empty($result)) {
  690. if(true !== $sepa && 1==$options['limit']) return reset($result[0]);
  691. foreach ($result as $val){
  692. $array[] = $val[$field];
  693. }
  694. return $array;
  695. }
  696. }
  697. return null;
  698. }
  699. /**
  700. * Create a data object But is not saved to the database
  701. * @access public
  702. * @param mixed $data Create a data
  703. * @param string $type State
  704. * @return mixed
  705. */
  706. public function create($data='',$type='') {
  707. // If there are no values default to get POST data
  708. if(empty($data)) {
  709. $data = $_POST;
  710. }elseif(is_object($data)){
  711. $data = get_object_vars($data);
  712. }
  713. // Validating data
  714. if(empty($data) || !is_array($data)) {
  715. $this->error = L('_DATA_TYPE_INVALID_');
  716. return false;
  717. }
  718. // Check the field mapping
  719. $data = $this->parseFieldsMap($data,0);
  720. // State
  721. $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT);
  722. // Detection of legitimacy of the submitted field
  723. if(isset($this->options['field'])) { // $this->field('field1,field2...')->create()
  724. $fields = $this->options['field'];
  725. unset($this->options['field']);
  726. }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) {
  727. $fields = $this->insertFields;
  728. }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) {
  729. $fields = $this->updateFields;
  730. }
  731. if(isset($fields)) {
  732. if(is_string($fields)) {
  733. $fields = explode(',',$fields);
  734. }
  735. // Judge token validation fields
  736. if(C('TOKEN_ON')) $fields[] = C('TOKEN_NAME');
  737. foreach ($data as $key=>$val){
  738. if(!in_array($key,$fields)) {
  739. unset($data[$key]);
  740. }
  741. }
  742. }
  743. // Automatic data validation
  744. if(!$this->autoValidation($data,$type)) return false;
  745. // Form token validation
  746. if(C('TOKEN_ON') && !$this->autoCheckToken($data)) {
  747. $this->error = L('_TOKEN_ERROR_');
  748. return false;
  749. }
  750. // Validation complete generated data objects
  751. if($this->autoCheckFields) { // Open field test You filter the illegal field data
  752. $fields = $this->getDbFields();
  753. foreach ($data as $key=>$val){
  754. if(!in_array($key,$fields)) {
  755. unset($data[$key]);
  756. }elseif(MAGIC_QUOTES_GPC && is_string($val)){
  757. $data[$key] = stripslashes($val);
  758. }
  759. }
  760. }
  761. // Create complete automated treatment of the data
  762. $this->autoOperation($data,$type);
  763. // The current data object assignment
  764. $this->data = $data;
  765. // Return the data created for other calls
  766. return $data;
  767. }
  768. // Automatic form validation token
  769. // TODO ajax no refresh multiple submissions temporarily unable to meet
  770. public function autoCheckToken($data) {
  771. if(C('TOKEN_ON')){
  772. $name = C('TOKEN_NAME');
  773. if(!isset($data[$name]) || !isset($_SESSION[$name])) { // Invalid token data
  774. return false;
  775. }
  776. // Token Authentication
  777. list($key,$value) = explode('_',$data[$name]);
  778. if($value && $_SESSION[$name][$key] === $value) { // Prevent duplicate submission
  779. unset($_SESSION[$name][$key]); // Verification is complete destroys the session
  780. return true;
  781. }
  782. // Open TOKEN reset
  783. if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]);
  784. return false;
  785. }
  786. return true;
  787. }
  788. /**
  789. * Validate data using regular
  790. * @access public
  791. * @param string $value To verify the data
  792. * @param string $rule Validation rules
  793. * @return boolean
  794. */
  795. public function regex($value,$rule) {
  796. $validate = array(
  797. 'require' => '/.+/',
  798. 'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
  799. 'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
  800. 'currency' => '/^\d+(\.\d+)?$/',
  801. 'number' => '/^\d+$/',
  802. 'zip' => '/^\d{6}$/',
  803. 'integer' => '/^[-\+]?\d+$/',
  804. 'double' => '/^[-\+]?\d+(\.\d+)?$/',
  805. 'english' => '/^[A-Za-z]+$/',
  806. );
  807. // Check whether there is a built-in regular expression
  808. if(isset($validate[strtolower($rule)]))
  809. $rule = $validate[strtolower($rule)];
  810. return preg_match($rule,$value)===1;
  811. }
  812. /**
  813. * Automatic Form Processing
  814. * @access public
  815. * @param array $data Create a data
  816. * @param string $type Create type
  817. * @return mixed
  818. */
  819. private function autoOperation(&$data,$type) {
  820. if(!empty($this->options['auto'])) {
  821. $_auto = $this->options['auto'];
  822. unset($this->options['auto']);
  823. }elseif(!empty($this->_auto)){
  824. $_auto = $this->_auto;
  825. }
  826. // Autofill
  827. if(isset($_auto)) {
  828. foreach ($_auto as $auto){
  829. // Fill Factor Definition Format
  830. // array('field','Fill Content','Fill Conditions','Additional rules',[Additional parameters])
  831. if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // The default is automatically populated when new
  832. if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) {
  833. switch(trim($auto[3])) {
  834. case 'function': // Use function to fill Value of the field as a parameter
  835. case 'callback': // Using callback method
  836. $args = isset($auto[4])?(array)$auto[4]:array();
  837. if(isset($data[$auto[0]])) {
  838. array_unshift($args,$data[$auto[0]]);
  839. }
  840. if('function'==$auto[3]) {
  841. $data[$auto[0]] = call_user_func_array($auto[1], $args);
  842. }else{
  843. $data[$auto[0]] = call_user_func_array(array(&$this,$auto[1]), $args);
  844. }
  845. break;
  846. case 'field': // The value used to fill other fields
  847. $data[$auto[0]] = $data[$auto[1]];
  848. break;
  849. case 'ignore': // Ignore empty
  850. if(''===$data[$auto[0]])
  851. unset($data[$auto[0]]);
  852. break;
  853. case 'string':
  854. default: // The default padding as a string
  855. $data[$auto[0]] = $auto[1];
  856. }
  857. if(false === $data[$auto[0]] ) unset($data[$auto[0]]);
  858. }
  859. }
  860. }
  861. return $data;
  862. }
  863. /**
  864. * Automatic form validation
  865. * @access protected
  866. * @param array $data Create a data
  867. * @param string $type Create type
  868. * @return boolean
  869. */
  870. protected function autoValidation($data,$type) {
  871. if(!empty($this->options['validate'])) {
  872. $_validate = $this->options['validate'];
  873. unset($this->options['validate']);
  874. }elseif(!empty($this->_validate)){
  875. $_validate = $this->_validate;
  876. }
  877. // Property Validation
  878. if(isset($_validate)) { // If you set up automatic data validation data validation is carried out
  879. if($this->patchValidate) { // Reset validation error message
  880. $this->error = array();
  881. }
  882. foreach($_validate as $key=>$val) {
  883. // Verify factor Definition Format
  884. // array(field,rule,message,condition,type,when,params)
  885. // Determine whether validation is performed
  886. if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) {
  887. if(0==strpos($val[2],'{%') && strpos($val[2],'}'))
  888. // Support multi-language message Use {%Language definition} Mode
  889. $val[2] = L(substr($val[2],2,-1));
  890. $val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE;
  891. $val[4] = isset($val[4])?$val[4]:'regex';
  892. // Determine the validation criteria
  893. switch($val[3]) {
  894. case self::MUST_VALIDATE: // Must verify Regardless of whether the form has set this field
  895. if(false === $this->_validationField($data,$val))
  896. return false;
  897. break;
  898. case self::VALUE_VALIDATE: // Value is not empty when it is verified
  899. if('' != trim($data[$val[0]]))
  900. if(false === $this->_validationField($data,$val))
  901. return false;
  902. break;
  903. default: // Default form field validation
  904. if(isset($data[$val[0]]))
  905. if(false === $this->_validationField($data,$val))
  906. return false;
  907. }
  908. }
  909. }
  910. // Batch validation when the last error
  911. if(!empty($this->error)) return false;
  912. }
  913. return true;
  914. }
  915. /**
  916. * Validate form fields Support batch validation
  917. * If the batch validation returns an array of error information
  918. * @access protected
  919. * @param array $data Create a data
  920. * @param array $val Authentication factors
  921. * @return boolean
  922. */
  923. protected function _validationField($data,$val) {
  924. if(false === $this->_validationFieldItem($data,$val)){
  925. if($this->patchValidate) {
  926. $this->error[$val[0]] = $val[2];
  927. }else{
  928. $this->error = $val[2];
  929. return false;
  930. }
  931. }
  932. return ;
  933. }
  934. /**
  935. * Based on validation factor authentication field
  936. * @access protected
  937. * @param array $data Create a data
  938. * @param array $val Authentication factors
  939. * @return boolean
  940. */
  941. protected function _validationFieldItem($data,$val) {
  942. switch(strtolower(trim($val[4]))) {
  943. case 'function':// Validation using function
  944. case 'callback':// Calling methods of verification
  945. $args = isset($val[6])?(array)$val[6]:array();
  946. if(is_string($val[0]) && strpos($val[0], ','))
  947. $val[0] = explode(',', $val[0]);
  948. if(is_array($val[0])){
  949. // Support multiple-field validation
  950. foreach($val[0] as $field)
  951. $_data[$field] = $data[$field];
  952. array_unshift($args, $_data);
  953. }else{
  954. array_unshift($args, $data[$val[0]]);
  955. }
  956. if('function'==$val[4]) {
  957. return call_user_func_array($val[1], $args);
  958. }else{
  959. return call_user_func_array(array(&$this, $val[1]), $args);
  960. }
  961. case 'confirm': // Verify that the two fields is the same
  962. return $data[$val[0]] == $data[$val[1]];
  963. case 'unique': // To verify that a value is unique
  964. if(is_string($val[0]) && strpos($val[0],','))
  965. $val[0] = explode(',',$val[0]);
  966. $map = array();
  967. if(is_array($val[0])) {
  968. // Support multiple-field validation
  969. foreach ($val[0] as $field)
  970. $map[$field] = $data[$field];
  971. }else{
  972. $map[$val[0]] = $data[$val[0]];
  973. }
  974. if(!empty($data[$this->getPk()])) { // Sound editing when validation only
  975. $map[$this->getPk()] = array('neq',$data[$this->getPk()]);
  976. }
  977. if($this->where($map)->find()) return false;
  978. return true;
  979. default: // Check additional rule
  980. return $this->check($data[$val[0]],$val[1],$val[4]);
  981. }
  982. }
  983. /**
  984. * Validating data Support in between equal length regex expire ip_allow ip_deny
  985. * @access public
  986. * @param string $value Validating data
  987. * @param mixed $rule Validation expression
  988. * @param string $type Authentication methods supported Defaults to verify
  989. * @return boolean
  990. */
  991. public function check($value,$rule,$type='regex'){
  992. $type = strtolower(trim($type));
  993. switch($type) {
  994. case 'in': // Verifies that a specified range A comma-delimited string or array
  995. case 'notin':
  996. $range = is_array($rule)? $rule : explode(',',$rule);
  997. return $type == 'in' ? in_array($value ,$range) : !in_array($value ,$range);
  998. case 'between': // Verify a range
  999. case 'notbetween': // Verify that is not in a range
  1000. if (is_array($rule)){
  1001. $min = $rule[0];
  1002. $max = $rule[1];
  1003. }else{
  1004. list($min,$max) = explode(',',$rule);
  1005. }
  1006. return $type == 'between' ? $value>=$min && $value<=$max : $value<$min || $value>$max;
  1007. case 'equal': // Verify that equal to a value
  1008. case 'notequal': // Verify that equal to a value
  1009. return $type == 'equal' ? $value == $rule : $value != $rule;
  1010. case 'length': // Verify the length
  1011. $length = mb_strlen($value,'utf-8'); // Current data length
  1012. if(strpos($rule,',')) { // Length range
  1013. list($min,$max) = explode(',',$rule);
  1014. return $length >= $min && $length <= $max;
  1015. }else{// Specified length
  1016. return $length == $rule;
  1017. }
  1018. case 'expire':
  1019. list($start,$end) = explode(',',$rule);
  1020. if(!is_numeric($start)) $start = strtotime($start);
  1021. if(!is_numeric($end)) $end = strtotime($end);
  1022. return NOW_TIME >= $start && NOW_TIME <= $end;
  1023. case 'ip_allow': // IP Operating license verified
  1024. return in_array(get_client_ip(),explode(',',$rule));
  1025. case 'ip_deny': // IP Action to suppress validation
  1026. return !in_array(get_client_ip(),explode(',',$rule));
  1027. case 'regex':
  1028. default: // Default use regular verification You can use validation class defined in the Authentication Name
  1029. // Check additional rule
  1030. return $this->regex($value,$rule);
  1031. }
  1032. }
  1033. /**
  1034. * SQL Query
  1035. * @access public
  1036. * @param string $sql SQL commands
  1037. * @param mixed $parse The need for parsing the SQL
  1038. * @return mixed
  1039. */
  1040. public function query($sql,$parse=false) {
  1041. if(!is_bool($parse) && !is_array($parse)) {
  1042. $parse = func_get_args();
  1043. array_shift($parse);
  1044. }
  1045. $sql = $this->parseSql($sql,$parse);
  1046. return $this->db->query($sql);
  1047. }
  1048. /**
  1049. * Executing SQL statements
  1050. * @access public
  1051. * @param string $sql SQL commands
  1052. * @param mixed $parse The need for parsing the SQL
  1053. * @return false | integer
  1054. */
  1055. public function execute($sql,$parse=false) {
  1056. if(!is_bool($parse) && !is_array($parse)) {
  1057. $parse = func_get_args();
  1058. array_shift($parse);
  1059. }
  1060. $sql = $this->parseSql($sql,$parse);
  1061. return $this->db->execute($sql);
  1062. }
  1063. /**
  1064. * Parsing the SQL statement
  1065. * @access public
  1066. * @param string $sql SQL commands
  1067. * @param boolean $parse The need for parsing the SQL
  1068. * @return string
  1069. */
  1070. protected function parseSql($sql,$parse) {
  1071. // Analysis Expressions
  1072. if(true === $parse) {
  1073. $options = $this->_parseOptions();
  1074. $sql = $this->db->parseSql($sql,$options);
  1075. }elseif(is_array($parse)){ // SQL preprocessing
  1076. $sql = vsprintf($sql,$parse);
  1077. }else{
  1078. $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
  1079. }
  1080. $this->db->setModel($this->name);
  1081. return $sql;
  1082. }
  1083. /**
  1084. * Switch the current database connection
  1085. * @access public
  1086. * @param integer $linkNum Serial Connection
  1087. * @param mixed $config Database connection information
  1088. * @param array $params Model parameters
  1089. * @return Model
  1090. */
  1091. public function db($linkNum='',$config='',$params=array()){
  1092. if(''===$linkNum && $this->db) {
  1093. return $this->db;
  1094. }
  1095. static $_linkNum = array();
  1096. static $_db = array();
  1097. if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $config && $_linkNum[$linkNum]!=$config) ) {
  1098. // Create a new instance
  1099. if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // Support read configuration parameters
  1100. $config = C($config);
  1101. }
  1102. $_db[$linkNum] = Db::getInstance($config);
  1103. }elseif(NULL === $config){
  1104. $_db[$linkNum]->close(); // Close the database connection
  1105. unset($_db[$linkNum]);
  1106. return ;
  1107. }
  1108. if(!empty($params)) {
  1109. if(is_string($params)) parse_str($params,$params);
  1110. foreach ($params as $name=>$value){
  1111. $this->setProperty($name,$value);
  1112. }
  1113. }
  1114. // Record Connection Information
  1115. $_linkNum[$linkNum] = $config;
  1116. // Switching the database connection
  1117. $this->db = $_db[$linkNum];
  1118. $this->_after_db();
  1119. // Field testing
  1120. if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo();
  1121. return $this;
  1122. }
  1123. // Database callback method after switching
  1124. protected function _after_db() {}
  1125. /**
  1126. * Get current data object name
  1127. * @access public
  1128. * @return string
  1129. */
  1130. public function getModelName() {
  1131. if(empty($this->name))
  1132. $this->name = substr(get_class($this),0,-5);
  1133. return $this->name;
  1134. }
  1135. /**
  1136. * Get complete data table name
  1137. * @access public
  1138. * @return string
  1139. */
  1140. public function getTableName() {
  1141. if(empty($this->trueTableName)) {
  1142. $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : '';
  1143. if(!empty($this->tableName)) {
  1144. $tableName .= $this->tableName;
  1145. }else{
  1146. $tableName .= ($this->name);
  1147. }
  1148. $this->trueTableName = ($tableName);
  1149. }
  1150. return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName;
  1151. }
  1152. /**
  1153. * Start transaction
  1154. * @access public
  1155. * @return void
  1156. */
  1157. public function startTrans() {
  1158. $this->commit();
  1159. $this->db->startTrans();
  1160. return ;
  1161. }
  1162. /**
  1163. * Commit the transaction
  1164. * @access public
  1165. * @return boolean
  1166. */
  1167. public function commit() {
  1168. return $this->db->commit();
  1169. }
  1170. /**
  1171. * Transaction rollback
  1172. * @access public
  1173. * @return boolean
  1174. */
  1175. public function rollback() {
  1176. return $this->db->rollback();
  1177. }
  1178. /**
  1179. * Returns an error message model
  1180. * @access public
  1181. * @return string
  1182. */
  1183. public function getError(){
  1184. return $this->error;
  1185. }
  1186. /**
  1187. * Returns the database error message
  1188. * @access public
  1189. * @return string
  1190. */
  1191. public function getDbError() {
  1192. return $this->db->getError();
  1193. }
  1194. /**
  1195. * Returns the last inserted ID
  1196. * @access public
  1197. * @return string
  1198. */
  1199. public function getLastInsID() {
  1200. return $this->db->getLastInsID();
  1201. }
  1202. /**
  1203. * Returns the last executed sql statement
  1204. * @access public
  1205. * @return string
  1206. */
  1207. public function getLastSql() {
  1208. return $this->db->getLastSql($this->name);
  1209. }
  1210. // Given getLastSql more common Increase _sql Aliases
  1211. public function _sql(){
  1212. return $this->getLastSql();
  1213. }
  1214. /**
  1215. * Get the name of the primary key
  1216. * @access public
  1217. * @return string
  1218. */
  1219. public function getPk() {
  1220. return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk;
  1221. }
  1222. /**
  1223. * Field information for a data sheet
  1224. * @access public
  1225. * @return array
  1226. */
  1227. public function getDbFields(){
  1228. if(isset($this->options['table'])) {// Dynamically specify the table name
  1229. $fields = $this->db->getFields($this->options['table']);
  1230. return $fields?array_keys($fields):false;
  1231. }
  1232. if($this->fields) {
  1233. $fields = $this->fields;
  1234. unset($fields['_autoinc'],$fields['_pk'],$fields['_type'],$fields['_version']);
  1235. return $fields;
  1236. }
  1237. return false;
  1238. }
  1239. /**
  1240. * Set the value of the data object
  1241. * @access public
  1242. * @param mixed $data Data
  1243. * @return Model
  1244. */
  1245. public function data($data=''){
  1246. if('' === $data && !empty($this->data)) {
  1247. return $this->data;
  1248. }
  1249. if(is_object($data)){
  1250. $data = get_object_vars($data);
  1251. }elseif(is_string($data)){
  1252. parse_str($data,$data);
  1253. }elseif(!is_array($data)){
  1254. throw_exception(L('_DATA_TYPE_INVALID_'));
  1255. }
  1256. $this->data = $data;
  1257. return $this;
  1258. }
  1259. /**
  1260. * Querying SQL assembly join
  1261. * @access public
  1262. * @param mixed $join
  1263. * @return Model
  1264. */
  1265. public function join($join) {
  1266. if(is_array($join)) {
  1267. $this->options['join'] = $join;
  1268. }elseif(!empty($join)) {
  1269. $this->options['join'][] = $join;
  1270. }
  1271. return $this;
  1272. }
  1273. /**
  1274. * Querying SQL assembly union
  1275. * @access public
  1276. * @param mixed $union
  1277. * @param boolean $all
  1278. * @return Model
  1279. */
  1280. public function union($union,$all=false) {
  1281. if(empty($union)) return $this;
  1282. if($all) {
  1283. $this->options['union']['_all'] = true;
  1284. }
  1285. if(is_object($union)) {
  1286. $union = get_object_vars($union);
  1287. }
  1288. // Conversion union expression
  1289. if(is_string($union) ) {
  1290. $options = $union;
  1291. }elseif(is_array($union)){
  1292. if(isset($union[0])) {
  1293. $this->options['union'] = array_merge($this->options['union'],$union);
  1294. return $this;
  1295. }else{
  1296. $options = $union;
  1297. }
  1298. }else{
  1299. throw_exception(L('_DATA_TYPE_INVALID_'));
  1300. }
  1301. $this->options['union'][] = $options;
  1302. return $this;
  1303. }
  1304. /**
  1305. * Query Cache
  1306. * @access public
  1307. * @param mixed $key
  1308. * @param integer $expire
  1309. * @param string $type
  1310. * @return Model
  1311. */
  1312. public function cache($key=true,$expire=null,$type=''){
  1313. if(false !== $key)
  1314. $this->options['cache'] = array('key'=>$key,'expire'=>$expire,'type'=>$type);
  1315. return $this;
  1316. }
  1317. /**
  1318. * Specifies the query field Support field exclusion
  1319. * @access public
  1320. * @param mixed $field
  1321. * @param boolean $except Whether the exclusion
  1322. * @return Model
  1323. */
  1324. public function field($field,$except=false){
  1325. if(true === $field) {// Get all the fields
  1326. $fields = $this->getDbFields();
  1327. $field = $fields?$fields:'*';
  1328. }elseif($except) {// Fields excluded
  1329. if(is_string($field)) {
  1330. $field = explode(',',$field);
  1331. }
  1332. $fields = $this->getDbFields();
  1333. $field = $fields?array_diff($fields,$field):$field;
  1334. }
  1335. $this->options['field'] = $field;
  1336. return $this;
  1337. }
  1338. /**
  1339. * Calling a named range
  1340. * @access public
  1341. * @param mixed $scope Named Range Name Support multiple and direct definition
  1342. * @param array $args Parameter
  1343. * @return Model
  1344. */
  1345. public function scope($scope='',$args=NULL){
  1346. if('' === $scope) {
  1347. if(isset($this->_scope['default'])) {
  1348. // Default naming scope
  1349. $options = $this->_scope['default'];
  1350. }else{
  1351. return $this;
  1352. }
  1353. }elseif(is_string($scope)){ // Support multiple named ranges called separated by commas
  1354. $scopes = explode(',',$scope);
  1355. $options = array();
  1356. foreach ($scopes as $name){
  1357. if(!isset($this->_scope[$name])) continue;
  1358. $options = array_merge($options,$this->_scope[$name]);
  1359. }
  1360. if(!empty($args) && is_array($args)) {
  1361. $options = array_merge($options,$args);
  1362. }
  1363. }elseif(is_array($scope)){ // Directly into a named range defined
  1364. $options = $scope;
  1365. }
  1366. if(is_array($options) && !empty($options)){
  1367. $this->options = array_merge($this->options,array_change_key_case($options));
  1368. }
  1369. return $this;
  1370. }
  1371. /**
  1372. * Specify the query criteria Support security filtering
  1373. * @access public
  1374. * @param mixed $where Conditional Expressions
  1375. * @param mixed $parse Pretreatment parameters
  1376. * @return Model
  1377. */
  1378. public function where($where,$parse=null){
  1379. if(!is_null($parse) && is_string($where)) {
  1380. if(!is_array($parse)) {
  1381. $parse = func_get_args();
  1382. array_shift($parse);
  1383. }
  1384. $parse = array_map(array($this->db,'escapeString'),$parse);
  1385. $where = vsprintf($where,$parse);
  1386. }elseif(is_object($where)){
  1387. $where = get_object_vars($where);
  1388. }
  1389. if(is_string($where) && '' != $where){
  1390. $map = array();
  1391. $map['_string'] = $where;
  1392. $where = $map;
  1393. }
  1394. if(isset($this->options['where'])){
  1395. $this->options['where'] = array_merge($this->options['where'],$where);
  1396. }else{
  1397. $this->options['where'] = $where;
  1398. }
  1399. return $this;
  1400. }
  1401. /**
  1402. * Specifies the number of queries
  1403. * @access public
  1404. * @param mixed $offset Starting position
  1405. * @param mixed $length Number of queries
  1406. * @return Model
  1407. */
  1408. public function limit($offset,$length=null){
  1409. $this->options['limit'] = is_null($length)?$offset:$offset.','.$length;
  1410. return $this;
  1411. }
  1412. /**
  1413. * Specifies the paging
  1414. * @access public
  1415. * @param mixed $page Pages
  1416. * @param mixed $listRows Number per page
  1417. * @return Model
  1418. */
  1419. public function page($page,$listRows=null){
  1420. $this->options['page'] = is_null($listRows)?$page:$page.','.$listRows;
  1421. return $this;
  1422. }
  1423. /**
  1424. * Query Comments
  1425. * @access public
  1426. * @param string $comment Note
  1427. * @return Model
  1428. */
  1429. public function comment($comment){
  1430. $this->options['comment'] = $comment;
  1431. return $this;
  1432. }
  1433. /**
  1434. * Set model attribute values
  1435. * @access public
  1436. * @param string $name Name
  1437. * @param mixed $value Value
  1438. * @return Model
  1439. */
  1440. public function setProperty($name,$value) {
  1441. if(property_exists($this,$name))
  1442. $this->$name = $value;
  1443. return $this;
  1444. }
  1445. }