PageRenderTime 23ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Controller/Data/Array.php

http://github.com/atk4/atk4
PHP | 212 lines | 180 code | 24 blank | 8 comment | 25 complexity | 2fdbf41ad4d181f370528584c7685290 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * Undocumented
  4. */
  5. class Controller_Data_Array extends Controller_Data
  6. {
  7. public $supportConditions = true;
  8. public $supportLimit = true;
  9. public $supportOrder = false;
  10. public $supportOperators = array(
  11. '=' => true,
  12. '>' => true,
  13. '>=' => true,
  14. '<=' => true,
  15. '<' => true,
  16. '!=' => true,
  17. 'like' => true
  18. );
  19. public function setSource($model, $table)
  20. {
  21. if (!is_array($table)) {
  22. throw $this->exception('Wrong type: expected array')
  23. ->addMoreInfo('source', $table);
  24. }
  25. if (!$model->hasMethod('push')) {
  26. $model->addMethod('push', $this);
  27. }
  28. // convert single dimension arrays
  29. reset($table);
  30. list(, $firstrow) = @each($table);
  31. if (!is_array($firstrow)) {
  32. // assuming that this array needs to be converted
  33. foreach ($table as $key => &$name) {
  34. $name = array($model->id_field => $key, $model->title_field => $name);
  35. }
  36. return parent::setSource($model, $table);
  37. }
  38. $data = array();
  39. foreach ($table as $key => $row) {
  40. $id = isset($row[$model->id_field]) ? $row[$model->id_field] : $key;
  41. $data[$id] = $row;
  42. }
  43. return parent::setSource($model, $data);
  44. }
  45. public function save($model, $id, $data)
  46. {
  47. $oldId = $id;
  48. if (is_null($id)) { // insert
  49. $newId = $data[$model->id_field] ?: $this->generateNewId($model);
  50. if (isset($model->_table[$this->short_name][$newId])) {
  51. throw $this->exception('This id is already used. Load the model before')
  52. ->addMoreInfo('id', $data[$model->id_field]);
  53. }
  54. } else { // update
  55. //unset($model->_table[$this->short_name][$oldId]);
  56. $newId = $id; //$data[$model->id_field];
  57. $data = array_merge($model->_table[$this->short_name][$newId], $data);
  58. }
  59. $data[$model->id_field] = $newId;
  60. $model->_table[$this->short_name][$newId] = $data;
  61. $model->data = $data;
  62. return $newId;
  63. }
  64. public function delete($model, $id)
  65. {
  66. unset($model->_table[$this->short_name][$id]);
  67. }
  68. public function loadById($model, $id)
  69. {
  70. if (isset($model->_table[$this->short_name][$id])) {
  71. $model->id = $id;
  72. $model->data = $model->_table[$this->short_name][$id];
  73. return true;
  74. }
  75. return false;
  76. }
  77. public function loadByConditions($model)
  78. {
  79. $ids = $this->getIdsFromConditions($model->_table[$this->short_name], $model->conditions);
  80. if (!empty($ids)) {
  81. $id = array_pop($ids);
  82. $model->id = $id;
  83. $model->data = $model->_table[$this->short_name][$id];
  84. }
  85. }
  86. public function deleteAll($model)
  87. {
  88. $ids = $this->getIdsFromConditions($model->_table[$this->short_name], $model->conditions);
  89. foreach ($ids as $id) {
  90. $this->delete($model, $id);
  91. }
  92. }
  93. public function prefetchAll($model)
  94. {
  95. // TODO: miss ordering...
  96. return $this->getIdsFromConditions($model->_table[$this->short_name], $model->conditions, $model->limit);
  97. }
  98. public function loadCurrent($model, &$cursor)
  99. {
  100. if (!$this->loadByID($model, array_shift($cursor))) {
  101. $model->id = null;
  102. $model->data = array();
  103. }
  104. }
  105. // resolve all conditions
  106. public function getIdsFromConditions($rows, $conditions, $limit = null)
  107. {
  108. $withLimit = !is_null($limit) && (is_array($limit) && !is_null($limit[0]));
  109. if ($withLimit) {
  110. $max = is_null($limit[1]) ? $limit[0] : ($limit[0] + $limit[1]);
  111. }
  112. $ids = array();
  113. foreach ($rows as $id => $row) {
  114. if ($id === '__ids__') {
  115. continue;
  116. }
  117. $valid = true;
  118. foreach ($conditions as $c) {
  119. if (!$this->isValid($row, $c)) {
  120. $valid = false;
  121. break;
  122. }
  123. }
  124. if ($valid === true) {
  125. $ids[] = $id;
  126. if ($withLimit && isset($max) && count($ids) > $max) {
  127. break;
  128. }
  129. }
  130. }
  131. if ($withLimit) {
  132. if ($limit[1] === null) {
  133. $ids = array_slice($ids, 0, $limit[0]);
  134. } else {
  135. $ids = array_slice($ids, $limit[0], $limit[1]);
  136. }
  137. }
  138. return $ids;
  139. }
  140. public function isValid($row, $conditions)
  141. {
  142. $value = $row[$conditions[0]];
  143. $op = $conditions[1];
  144. $expected = $conditions[2];
  145. switch ($op) {
  146. case '=':
  147. return $value === $expected;
  148. case '>':
  149. return $value > $expected;
  150. case '>=':
  151. return $value >= $expected;
  152. case '<=':
  153. return $value <= $expected;
  154. case '<':
  155. return $value < $expected;
  156. case '!=':
  157. return $value != $expected;
  158. case 'like':
  159. $pattern = '/^' . str_replace('%', '.*', preg_quote($expected, '/')) . '$/i';
  160. return (bool) preg_match($pattern, $value);
  161. default:
  162. throw $this->exception('Unknown operator')
  163. ->addMoreInfo('operator', $op);
  164. }
  165. }
  166. public function generateNewId($model)
  167. {
  168. $ids = array_keys($model->_table[$this->short_name]);
  169. $type = $model->getElement($model->id_field)->type();
  170. if (in_array($type, array('int', 'integer'))) {
  171. return count($ids) === 0 ? 1 : (max($ids) + 1);
  172. } elseif (in_array($type, array('str', 'string'))) {
  173. return uniqid();
  174. } else {
  175. throw $this->exception('Unknown id type')
  176. ->addMoreInfo('type', $type)
  177. ->addMoreInfo('support', array('int', 'str'));
  178. }
  179. }
  180. public function count($model)
  181. {
  182. return count($model->_table[$this->short_name]);
  183. }
  184. public function push($model, $row)
  185. {
  186. $model->_table[$this->short_name][] = $row;
  187. }
  188. }