You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
8.1 KiB

  1. <?php
  2. /**
  3. * Класс модели данных
  4. *
  5. * @copyright NetMonsters <team@netmonsters.ru>
  6. * @link http://netmonsters.ru
  7. * @package Majestic
  8. * @subpackage Model
  9. * @since 2011-11-11
  10. */
  11. /**
  12. * @property SqlDbDriver $db
  13. */
  14. abstract class SqlModel extends Model
  15. {
  16. const SELECT = 10;
  17. const DISTINCT = 11;
  18. const WHERE = 12;
  19. const ORDER = 13;
  20. const ORDER_TO_DESC = 14;
  21. const LIMIT = 15;
  22. const OFFSET = 16;
  23. protected static $criteria_data_keys = array(
  24. self::SELECT,
  25. self::DISTINCT,
  26. self::WHERE,
  27. self::ORDER,
  28. /** self::ORDER_TO_DESC, // no to be process in foreach criteria_data @see SqlModel::find() */
  29. self::LIMIT,
  30. /** self::OFFSET // no to be process in foreach criteria_data @see SqlModel::find() */
  31. );
  32. /**
  33. * @param string $ident
  34. * @return string Quoted identifier.
  35. */
  36. public function identify($ident)
  37. {
  38. return $this->db->quoteIdentifier($ident);
  39. }
  40. /**
  41. * @param mixed $value
  42. * @return string Quoted value.
  43. */
  44. public function quote($value)
  45. {
  46. return $this->db->quote($value);
  47. }
  48. /**
  49. * @param int $id
  50. * @return object
  51. */
  52. public function get($id)
  53. {
  54. $sql = 'SELECT * FROM :table WHERE :pk=?';
  55. return $this->fetch($sql, $id);
  56. }
  57. /**
  58. * @param array $data
  59. * @param mixed $where
  60. * @return int Number of affected rows
  61. */
  62. public function update($data, $where)
  63. {
  64. if (is_int($where) || $where === (string) (int) $where) {
  65. $where = $this->identify($this->key) . '=' . (int) $where;
  66. }
  67. return parent::update($data, $where);
  68. }
  69. /**
  70. * @param int $id Int id
  71. * @return int Number of affected rows
  72. */
  73. public function delete($id)
  74. {
  75. $where = $this->identify($this->key) . '=' . (int) $id;
  76. return $this->db->delete($this->table(), $where);
  77. }
  78. /**
  79. * Creates order sql string
  80. *
  81. * @param array $params
  82. * @param array $sortable
  83. * @return string
  84. */
  85. protected function order($params, $sortable = array('id'))
  86. {
  87. $sql = '';
  88. if (isset($params['sort'])) {
  89. $order = (isset($params['order']) && $params['order'] == 'desc') ? 'DESC' : 'ASC';
  90. if (in_array($params['sort'], $sortable)) {
  91. $sql = ' ORDER BY ' . $this->identify($params['sort']) . ' ' . $order;
  92. }
  93. }
  94. return $sql;
  95. }
  96. /**
  97. * Searches using like
  98. *
  99. * @param array $params
  100. * @param array $searchable
  101. * @param string $table_prefix
  102. * @return string
  103. */
  104. protected function search($params, $searchable = array('id'), $table_prefix = '')
  105. {
  106. $sql = '';
  107. if (isset($params['q']) && isset($params['qt']) && in_array($params['qt'], $searchable)) {
  108. if ($table_prefix) {
  109. $sql = $table_prefix . '.';
  110. }
  111. $sql .= $this->identify($params['qt']) . ' LIKE ' . $this->quote('%' . $params['q'] . '%');
  112. }
  113. return $sql;
  114. }
  115. /**
  116. * This method appends to params table and primary key.
  117. * So they can be accessed through `:table` and `:pk` placeholders.
  118. *
  119. * @param string $sql
  120. * @param array $params
  121. * @return DbStatement
  122. */
  123. protected function query($sql, $params = array())
  124. {
  125. if (!is_array($params)) {
  126. $params = array($params);
  127. }
  128. $params = array(
  129. 'table' => new DbExpr($this->identify($this->table())),
  130. 'pk' => new DbExpr($this->identify($this->key)),
  131. ) + $params;
  132. return $this->db->query($sql, $params);
  133. }
  134. /**
  135. * @param string $data Request
  136. * @param array $params Request parameters
  137. * @param string $field Requested field name
  138. * @param CacheKey $cache_key Key for caching in
  139. * @return mixed
  140. */
  141. protected function fetchField($data, $params = array(), $field, $cache_key = null)
  142. {
  143. if (!$cache_key || !$result = $cache_key->get()) {
  144. $result = $this->query($data, $params)->fetchField($field);
  145. if ($cache_key) {
  146. $cache_key->set($result);
  147. }
  148. }
  149. return $result;
  150. }
  151. /**
  152. * @param string $data Request
  153. * @param array $params Request parameters
  154. * @param CacheKey $cache_key Key for caching in
  155. * @return mixed
  156. */
  157. protected function fetch($data, $params = array(), $cache_key = null)
  158. {
  159. if (!$cache_key || !$result = $cache_key->get()) {
  160. $result = $this->query($data, $params)->fetch();
  161. if ($cache_key) {
  162. $cache_key->set($result);
  163. }
  164. }
  165. return $result;
  166. }
  167. /**
  168. * @param string $data
  169. * @param array $params
  170. * @param CacheKey $cache_key
  171. * @return array
  172. */
  173. protected function fetchAll($data, $params = array(), $cache_key = null)
  174. {
  175. if (!$cache_key || !$result = $cache_key->get()) {
  176. $result = $this->query($data, $params)->fetchAll();
  177. if ($cache_key) {
  178. $cache_key->set($result);
  179. }
  180. }
  181. return $result;
  182. }
  183. /**
  184. * @param $criteria SqlCriteria
  185. * @return string Sql string expression
  186. */
  187. protected function criteria($criteria)
  188. {
  189. foreach ($criteria->select as $field => &$term) {
  190. if (is_int($field)) {
  191. $term = $this->db->quoteIdentifier($term);
  192. } else {
  193. $term = $this->db->quoteIdentifier($field) . ' as ' . $this->db->quoteIdentifier($term);
  194. }
  195. }
  196. foreach ($criteria->where as $cond => &$term) {
  197. $term = $this->db->quoteInto($cond, $term);
  198. }
  199. foreach ($criteria->order as $field => $term) {
  200. if (!is_int($field) && $term == 'desc') {
  201. $term = $term = $this->db->quoteIdentifier($field) . ' DESC';
  202. } else {
  203. $term = $this->db->quoteIdentifier($term);
  204. }
  205. }
  206. if ($criteria->distinct != '') {
  207. $criteria->distinct = 'DISTINCT ' . $this->db->quoteIdentifier($criteria->distinct);
  208. }
  209. return 'SELECT ' . (($criteria->distinct) ? $criteria->distinct : implode(',', $criteria->select))
  210. . ' FROM ' . $this->db->quoteIdentifier($this->table)
  211. . (($criteria->where) ? (' WHERE ' . implode(' AND ', $criteria->where)) : '')
  212. . (($criteria->order) ? (' ORDER BY ' . implode(',', $criteria->order)) : '')
  213. . (($criteria->limit) ? (' LIMIT ' . implode(',',array_map(function($item){return intval($item);},explode(',',$criteria->limit)))) : '');
  214. }
  215. /**
  216. * @param $criteria_data array
  217. * @ex array(
  218. * SqlModel::SELECT => '*',
  219. * SqlModel::WHERE => array('field=?', 1),
  220. * SqlModel::ORDER => array('last_name', 'first_name'),
  221. * SqlModel::ORDER_TO_DESC => array('last_name'),
  222. * SqlModel::LIMIT => 10)
  223. * @return mixed|DbStatement[]
  224. */
  225. public function find($criteria_data)
  226. {
  227. $criteria = new SqlCriteria();
  228. foreach (self::$criteria_data_keys as $criteria_data_key) {
  229. if (isset($criteria_data[$criteria_data_key])) {
  230. $value = $criteria_data[$criteria_data_key];
  231. switch ($criteria_data_key) {
  232. case self::SELECT:
  233. $criteria->select($value);
  234. break;
  235. case self::DISTINCT:
  236. $criteria->distinct($value);
  237. break;
  238. case self::WHERE:
  239. $criteria->where($value);
  240. break;
  241. case self::ORDER:
  242. $criteria->order($value, ((isset($criteria_data[self::ORDER_TO_DESC])) ? $criteria_data[self::ORDER_TO_DESC] : null));
  243. break;
  244. case self::LIMIT:
  245. $criteria->limit($value, ((isset($criteria_data[self::OFFSET])) ? $criteria_data[self::OFFSET] : null));
  246. break;
  247. }
  248. }
  249. }
  250. return self::fetchAll($this->criteria($criteria));
  251. }
  252. }