PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/protected/libs/DModel.php

https://github.com/smarteng/onenoteme
PHP | 530 lines | 316 code | 51 blank | 163 comment | 35 complexity | f3ff1be706d4ce0a17718f57e16174ff MD5 | raw file
  1. <?php
  2. /**
  3. * @author chendong
  4. *
  5. * @abstract
  6. * @version 1.0
  7. */
  8. abstract class DModel
  9. {
  10. private static $_models;
  11. private $_pk;
  12. private $_db;
  13. private $_cmd;
  14. private $_attributes;
  15. function __construct()
  16. {
  17. // @todo update insert 使用
  18. // $this->setIsNewRecord(true);
  19. $this->_pk = $this->pk();
  20. $this->init();
  21. }
  22. public function __set($name, $value)
  23. {
  24. if ($this->setAttribute($name, $value) === false) {
  25. $setter = 'set' . ucfirst(strtolower($name));
  26. if (method_exists($this, $setter))
  27. return $this->$setter($value);
  28. }
  29. }
  30. public function __get($name)
  31. {
  32. if (isset($this->_attributes[$name]))
  33. return $this->_attributes[$name];
  34. else {
  35. $getter = 'get' . ucfirst(strtolower($name));
  36. return $this->$getter();
  37. }
  38. }
  39. public function __isset($name)
  40. {
  41. $getter = 'get' . ucfirst(strtolower($name));
  42. return isset($this->_attributes[$name]) || method_exists($this, $getter) || false;
  43. }
  44. public function __unset($name)
  45. {
  46. $setter = 'set' . ucfirst(strtolower($name));
  47. $getter = 'get' . ucfirst(strtolower($name));
  48. if (in_array($name, $this->columns()))
  49. unset($this->_attributes[$name]);
  50. elseif (method_exists($this, $setter))
  51. $this->$setter(null);
  52. elseif (method_exists($this, $getter))
  53. throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
  54. array('{class}'=>get_class($this), '{property}'=>$name)));
  55. else
  56. throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
  57. array('{class}'=>get_class($this), '{property}'=>$name)));
  58. }
  59. /**
  60. * Initializes this model.
  61. */
  62. public function init()
  63. {
  64. }
  65. /**
  66. * Returns the static model of the specified DModel class.
  67. * @param string $class
  68. * @param Dmodel
  69. */
  70. public static function model($class = __CLASS__)
  71. {
  72. if (isset(self::$_models[$class]))
  73. return self::$_models[$class];
  74. else {
  75. $model = self::$_models[$class] = new $class(null);
  76. return $model;
  77. }
  78. }
  79. /**
  80. * Return app db component
  81. * @return CDbConnection
  82. */
  83. public function getDb()
  84. {
  85. if ($this->_db)
  86. return $this->_db;
  87. else
  88. return $this->_db = Yii::app()->getDb();
  89. }
  90. /**
  91. * return db command object
  92. * @param string $query
  93. * @return CDbCommand
  94. */
  95. public function getDbCommand($query = null)
  96. {
  97. if ($this->_cmd)
  98. return $this->_cmd;
  99. else
  100. return $this->_cmd = Yii::app()->getDb()->createCommand($query);
  101. }
  102. /**
  103. * Sets the parameters about query caching.
  104. * This is a shortcut method to {@link CDbConnection::cache()}.
  105. * It changes the query caching parameter of the {@link dbConnection} instance.
  106. * @param integer $duration the number of seconds that query results may remain valid in cache.
  107. * If this is 0, the caching will be disabled.
  108. * @param CCacheDependency $dependency the dependency that will be used when saving the query results into cache.
  109. * @param integer $queryCount number of SQL queries that need to be cached after calling this method. Defaults to 1,
  110. * meaning that the next SQL query will be cached.
  111. * @return DModel the active record instance itself.
  112. */
  113. public function cache($duration, $dependency=null, $queryCount=1)
  114. {
  115. $this->getDb()->cache($duration, $dependency, $queryCount);
  116. return $this;
  117. }
  118. /**
  119. * fetch the rows by pk
  120. * @param mixed $pk
  121. * @param mixed $select string|array
  122. * @param array $params
  123. * @param boolean $fetchAssociative
  124. * @return array the record found. Null if none is found.
  125. */
  126. public function queryByPk($pk, $select = '*', $params = array(), $fetchAssociative = true)
  127. {
  128. $cmd = $this->getDbCommand()
  129. ->select($select)
  130. ->where($this->pk() . ' = :value', array(':value'=>$pk));
  131. return $this->query($cmd, $params, $fetchAssociative);
  132. }
  133. /**
  134. * Executes the SQL statement and returns the first row of results.
  135. * @param CDbCommand $cmd
  136. * @param array $params
  137. * @param boolean $fetchAssociative
  138. * @return array the record found. Null if none is found.
  139. */
  140. public function query(CDbCommand $cmd, $params = array(), $fetchAssociative = true)
  141. {
  142. return $cmd->from($this->table() . ' t')
  143. ->limit(1)->queryRow($fetchAssociative, $params);
  144. }
  145. /**
  146. * Executes the SQL statement and returns all rows.
  147. * @param CDbCommand $cmd
  148. * @param array $params
  149. * @param boolean $fetchAssociative
  150. * @return array the record found. An empty array if none is found.
  151. */
  152. public function queryAll(CDbCommand $cmd, $params = array(), $fetchAssociative = true)
  153. {
  154. $this->beforeFind();
  155. $cmd->from($this->table() . ' t');
  156. return $cmd->queryAll($fetchAssociative, $params);
  157. }
  158. /**
  159. * fetch the rows by pk
  160. * @param mixed $pk
  161. * @param mixed $select string|array
  162. * @param array $params
  163. * @param boolean $fetchAssociative
  164. * @return DModel the record found. Null if none is found.
  165. */
  166. public function findByPk($pk, $select = '*', $params = array(), $fetchAssociative = true)
  167. {
  168. return $this->toModel($this->queryByPk($pk, $select, $params, $fetchAssociative));
  169. }
  170. /**
  171. * fetch the model
  172. * @param CDbCommand $cmd
  173. * @param array $params
  174. * @param boolean $fetchAssociative
  175. * @return DModel the record found. Null if none is found.
  176. */
  177. public function find(CDbCommand $cmd, $params = array(), $fetchAssociative = true)
  178. {
  179. return $this->toModel($this->query($cmd, $params, $fetchAssociative));
  180. }
  181. /**
  182. * fetch the models
  183. * @param CDbCommand $cmd
  184. * @param array $params
  185. * @param boolean $fetchAssociative
  186. * @return DModel the record found. Null if none is found.
  187. */
  188. public function findAll(CDbCommand $cmd, $params = array(), $fetchAssociative = true)
  189. {
  190. return $this->toModels($this->queryAll($cmd, $params, $fetchAssociative));
  191. }
  192. public function count($conditions = '', $params = array())
  193. {
  194. if ($conditions instanceof CDbCommand) {
  195. return $conditions->select('count(*)')
  196. ->from($this->table() . ' t')
  197. ->queryScalar();
  198. }
  199. $cmd = $this->getDbCommand()
  200. ->select('count(*)')
  201. ->from($this->table() . ' t');
  202. if ($conditions)
  203. $cmd->where($conditions, $params);
  204. return $cmd->queryScalar();
  205. }
  206. /**
  207. * init model
  208. * @return DModel
  209. */
  210. protected function instantiate()
  211. {
  212. $class = get_class($this);
  213. $model = new $class();
  214. return $model;
  215. }
  216. /**
  217. * make data array row to model
  218. * @param array $row
  219. * @param boolean $callAfterFind
  220. * @return DModel the dmodel object found. Null if no record is found.
  221. */
  222. public function toModel($row, $callAfterFind = true)
  223. {
  224. $this->beforeFind();
  225. if ($row !== false && is_array($row)) {
  226. $model = $this->instantiate();
  227. $model->init();
  228. foreach ($row as $key => $value)
  229. $model->$key = $value;
  230. if ($callAfterFind)
  231. $model->afterFind();
  232. return $model;
  233. }
  234. else
  235. return null;
  236. }
  237. /**
  238. * make data array row to models
  239. * @param array $row
  240. * @param boolean $callAfterFind
  241. * @return array array list of dmodels. An empty array is returned if none is found.
  242. */
  243. public function toModels($rows, $callAfterFind = true)
  244. {
  245. if ($rows) {
  246. foreach ($rows as $row) {
  247. if (is_array($row))
  248. $models[] = $this->toModel($row, $callAfterFind);
  249. else
  250. throw new CDbException('$row is not a associative array');
  251. }
  252. }
  253. else
  254. $models = array();
  255. return $models;
  256. }
  257. public function insert($attributes = null)
  258. {
  259. if ($this->beforeSave()) {
  260. $result = $this->getDbCommand()->insert($this->table(), $this->getAttributes($attributes)) > 0;
  261. if ($result)
  262. $this->{$this->pk()} = Yii::app()->db->getLastInsertID();
  263. return $result;
  264. }
  265. else
  266. return false;
  267. }
  268. /**
  269. * update the row
  270. * @param array $columns example: array(name => value)
  271. * @return boolean whether the deletion is successful.
  272. */
  273. public function update($attributes = null)
  274. {
  275. if ($this->beforeSave()) {
  276. $pk = $this->pk();
  277. $result = $this->updateByPk($this->$pk, $this->getAttributes($attributes)) > 0;
  278. $this->afterSave();
  279. return $result;
  280. }
  281. else
  282. return false;
  283. }
  284. public function updateByPk($pk, $columns, $conditions = '', $params = array())
  285. {
  286. if (is_numeric($pk) || is_string($pk))
  287. $pk = array($pk);
  288. $where = array('in', $this->pk(), $pk);
  289. if ($conditions)
  290. $where = array('and', $where, $conditions);
  291. return $this->updateAll($columns, $where, $params);
  292. }
  293. /**
  294. * update rows by attributes
  295. * @param array $attributes example array(name => value)
  296. * @param mixed $conditions string|array
  297. * @param array $params
  298. * @return integer number of rows affected by the execution.
  299. */
  300. public function updateAllByAttributes($columns, $attributes, $conditions = '', $params = array())
  301. {
  302. foreach ((array)$attributes as $key => $value)
  303. $where[] = "$key = :$key";
  304. $where = implode(' and ', $where);
  305. $where = array('and', $where, $conditions);
  306. $params = array_merge($params, $conditions);
  307. return $this->updateAll($columns, $conditions, $params);
  308. }
  309. /**
  310. * update the rows
  311. * @param array $columns example: array(name => value)
  312. * @param mixed $conditions string|array
  313. * @param array $params
  314. * @return integer number of rows affected by the execution.
  315. */
  316. public function updateAll($columns, $conditions = '', $params = array())
  317. {
  318. return $this->getDbCommand()->update($this->table(), $columns, $conditions, $params);
  319. }
  320. public function updateCounters(array $counters, $conditions, $params = array())
  321. {
  322. foreach ($counters as $key => $value)
  323. $columns[$key] = "$key + $value";
  324. return $this->getDbCommand()
  325. ->update($this->table(), $columns, $conditions, $params);
  326. }
  327. /**
  328. * delete the row
  329. * @return boolean whether the deletion is successful.
  330. */
  331. public function delete()
  332. {
  333. if ($this->beforeDelete()) {
  334. $pk = $this->pk();
  335. $result = $this->deleteByPk($this->$pk) > 0;
  336. $this->afterDelete();
  337. return (bool)$result;
  338. }
  339. else
  340. return false;
  341. }
  342. /**
  343. * delete the row by primary key
  344. * @param mixed $pk integer|string|array
  345. * @param mixed $conditions string|array
  346. * @param array $params
  347. * @return integer number of rows affected by the execution.
  348. */
  349. public function deleteByPk($pk, $conditions = '', $params = array())
  350. {
  351. if (is_numeric($pk) || is_string($pk))
  352. $pk = array($pk);
  353. $where = array('in', $this->pk(), $pk);
  354. if ($conditions)
  355. $where = array('and', $where, $conditions);
  356. return $this->deleteAll($where, $params);
  357. }
  358. /**
  359. * delete rows by attributes
  360. * @param array $attributes example array(name => value)
  361. * @param mixed $conditions string|array
  362. * @param array $params
  363. * @return integer number of rows affected by the execution.
  364. */
  365. public function deleteAllByAttributes($attributes, $conditions = '', $params = array())
  366. {
  367. foreach ((array)$attributes as $key => $value)
  368. $where[] = "$key = :$key";
  369. $where = implode(' and ', $where);
  370. $where = array('and', $where, $conditions);
  371. $params = array_merge($params, $conditions);
  372. return $this->deleteAll($conditions, $params);
  373. }
  374. /**
  375. * execute a delete sql
  376. * @param string|array $conditions
  377. * @param array $params
  378. * @return integer number of rows affected by the execution.
  379. */
  380. public function deleteAll($conditions = '', $params = array())
  381. {
  382. return $this->getDbCommand()->delete($this->table(), $conditions, $params);
  383. }
  384. /**
  385. * Checks whether this AR has the named attribute
  386. * @param string $name attribute name
  387. * @return boolean whether this AR has the named attribute (table column).
  388. */
  389. public function hasAttribute($name)
  390. {
  391. return in_array($name, $this->columns());
  392. }
  393. /**
  394. * Returns the named attribute value.
  395. * If this is a new record and the attribute is not set before,
  396. * the default column value will be returned.
  397. * If this record is the result of a query and the attribute is not loaded,
  398. * null will be returned.
  399. * You may also use $this->AttributeName to obtain the attribute value.
  400. * @param string $name the attribute name
  401. * @return mixed the attribute value. Null if the attribute is not set or does not exist.
  402. * @see hasAttribute
  403. */
  404. public function getAttribute($name)
  405. {
  406. if (property_exists($this, $name))
  407. return $this->$name;
  408. elseif (isset($this->_attributes[$name]))
  409. return $this->_attributes[$name];
  410. }
  411. /**
  412. * Sets the named attribute value.
  413. * You may also use $this->AttributeName to set the attribute value.
  414. * @param string $name the attribute name
  415. * @param mixed $value the attribute value.
  416. * @return boolean whether the attribute exists and the assignment is conducted successfully
  417. * @see hasAttribute
  418. */
  419. public function setAttribute($name, $value)
  420. {
  421. if (property_exists($this, $name))
  422. $this->$name = $value;
  423. elseif ($this->hasAttribute($name))
  424. $this->_attributes[$name] = $value;
  425. else
  426. return false;
  427. return true;
  428. }
  429. public function setAttributes($values)
  430. {
  431. if (!is_array($values)) return false;
  432. foreach ($values as $key => $value)
  433. $this->$key = $value;
  434. }
  435. public function getAttributes($names = true)
  436. {
  437. $attributes = $this->_attributes;
  438. foreach ($this->columns() as $column)
  439. if (property_exists($this, $column))
  440. $attributes[$column] = $this->$column;
  441. elseif ($names === true && !isset($attributes[$column]))
  442. $attributes[$column] = null;
  443. if (is_array($names)) {
  444. $attrs = array();
  445. foreach ($names as $name) {
  446. if (property_exists($this, $name))
  447. $attrs[$name] = $this->$name;
  448. else
  449. $attrs[$name] = isset($attributes[$name]) ? $attributes[$name] : null;
  450. }
  451. return $attrs;
  452. }
  453. else
  454. return $attributes;
  455. }
  456. protected function beforeFind()
  457. {
  458. }
  459. protected function afterFind()
  460. {
  461. }
  462. protected function beforeDelete()
  463. {
  464. return true;
  465. }
  466. protected function afterDelete()
  467. {
  468. }
  469. protected function beforeSave()
  470. {
  471. return true;
  472. }
  473. protected function afterSave()
  474. {
  475. }
  476. abstract public function table();
  477. abstract public function columns();
  478. abstract public function pk();
  479. }