PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/models/behaviors/super_find.php

http://github.com/jrbasso/super_find
PHP | 277 lines | 216 code | 11 blank | 50 comment | 46 complexity | c5536ff152160444a0c91ec4f42e96d0 MD5 | raw file
  1. <?php
  2. /**
  3. * Super Find Behavior
  4. *
  5. * Licensed under The MIT License
  6. * Redistributions of files must retain the above copyright notice.
  7. *
  8. * @link http://github.com/jrbasso/super_find
  9. * @package super_find
  10. * @subpackage super_find.models.behaviors
  11. * @since SuperFind v0.1
  12. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  13. */
  14. class SuperFindBehavior extends ModelBehavior {
  15. /**
  16. * Makes the find with the possibility of using conditions of all relationships
  17. *
  18. * @access public
  19. * @param object $Model Pointer to model
  20. * @param array $conditions SQL conditions array, or type of find operation (all / first / count /
  21. * neighbors / list / threaded)
  22. * @param mixed $fields Either a single string of a field name, or an array of field names, or
  23. * options for matching
  24. * @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC")
  25. * @param integer $recursive The number of levels deep to fetch associated records
  26. * @return array Array of records
  27. * @access public
  28. */
  29. function superFind(&$Model, $conditions = null, $fields = array(), $order = null, $recursive = null) {
  30. if (!is_string($conditions)) {
  31. $type = 'first';
  32. $query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1));
  33. } else {
  34. list($type, $query) = array($conditions, $fields);
  35. }
  36. $relations = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
  37. $originalRelations = array();
  38. foreach ($relations as $relation) {
  39. $originalRelations[$relation] = $Model->$relation;
  40. $extraFinds[$relation] = array();
  41. }
  42. if (isset($query['conditions'])) {
  43. if (!is_array($query['conditions'])) {
  44. $query['conditions'] = (array)$query['conditions'];
  45. }
  46. foreach ($query['conditions'] as $key => $value) {
  47. $originalKey = $key;
  48. $check =& $value;
  49. if (is_string($key)) {
  50. $check =& $key;
  51. }
  52. if (!preg_match('/^\w+\.\w+(\.\w+)*/', $check, $matches)) {
  53. continue;
  54. }
  55. $modelsName = explode('.', $matches[0]);
  56. array_pop($matches); // Remove the field name
  57. if ($modelsName[0] === $Model->alias) {
  58. if (count($modelsName) > 1) {
  59. $check = substr($check, strlen($modelsName[0]) + 1);
  60. unset($modelsName[0]);
  61. } else {
  62. continue;
  63. }
  64. }
  65. $mainModel = reset($modelsName);
  66. if (count($modelsName) < 3 && ($mainModel === $Model->alias || isset($Model->belongsTo[$mainModel]) || isset($Model->hasOne[$mainModel]))) {
  67. unset($query['conditions'][$originalKey]);
  68. if ($check === $key) {
  69. $query['conditions'][$check] = $value;
  70. } else {
  71. $query['conditions'][] = $check;
  72. }
  73. if ($mainModel !== $Model->alias) {
  74. if ($Model->Behaviors->attached('Containable')) {
  75. $query['contain'][] = $mainModel;
  76. if (isset($query['recursive'])) {
  77. unset($query['recursive']);
  78. }
  79. } else {
  80. if (isset($query['recursive'])) {
  81. if ($query['recursive'] < 0) {
  82. $query['recursive'] = 0;
  83. } else {
  84. $query['recursive'] = 0;
  85. }
  86. }
  87. }
  88. }
  89. continue;
  90. }
  91. if (isset($Model->hasMany[$mainModel], $Model->$mainModel)) {
  92. $extraFinds['hasMany'][$mainModel][$key] = $value;
  93. unset($query['conditions'][$originalKey]);
  94. } elseif (isset($Model->hasAndBelongsToMany[$mainModel], $Model->$mainModel)) {
  95. $extraFinds['hasAndBelongsToMany'][$mainModel][$key] = $value;
  96. unset($query['conditions'][$originalKey]);
  97. } else {
  98. if (count($modelsName) > 2) {
  99. if (isset($Model->belongsTo[$mainModel], $Model->$mainModel)) {
  100. $extraFinds['belongsTo'][$mainModel][$key] = $value;
  101. } elseif (isset($Model->hasOne[$mainModel], $Model->$mainModel)) {
  102. $extraFinds['hasOne'][$mainModel][$key] = $value;
  103. }
  104. unset($query['conditions'][$originalKey]);
  105. }
  106. }
  107. }
  108. $this->_subFindBelongsTo($extraFinds['belongsTo'], $Model, $query);
  109. $this->_subFindHasMany($extraFinds['hasMany'], $Model, $query);
  110. $this->_subFindHasAndBelongsToMany($extraFinds['hasAndBelongsToMany'], $Model, $query);
  111. }
  112. $return = $Model->find($type, $query);
  113. foreach ($relations as $relation) {
  114. $Model->$relation = $originalRelations[$relation];
  115. }
  116. return $return;
  117. }
  118. /**
  119. * Make sub finds to belongsTo assoc
  120. *
  121. * @access protected
  122. * @return void
  123. */
  124. function _subFindBelongsTo($data, &$Model, &$query) {
  125. foreach ($data as $modelName => $extraConditions) {
  126. $pk = $modelName . '.' . $Model->$modelName->primaryKey;
  127. $removeBehavior = false;
  128. if (!$Model->$modelName->Behaviors->attached('SuperFind')) {
  129. $removeBehavior = true;
  130. $Model->$modelName->Behaviors->attach('SuperFind.SuperFind');
  131. }
  132. $data = $Model->$modelName->superFind('all', array(
  133. 'fields' => array($pk),
  134. 'conditions' => $extraConditions,
  135. 'recursive' => -1
  136. ));
  137. if ($removeBehavior) {
  138. $Model->$modelName->Behaviors->detach('SuperFind.SuperFind');
  139. }
  140. if (empty($data)) {
  141. $query['conditions'] = '1 = 0';
  142. break;
  143. }
  144. $masterModelIds = array_unique(Set::extract('{n}.' . $pk, $data));
  145. $fk = $Model->belongsTo[$modelName]['foreignKey'];
  146. if (isset($query['conditions'][$fk])) {
  147. $query['conditions'][$fk] = array_intersect((array)$query['conditions'][$fk], $masterModelIds);
  148. } else {
  149. $query['conditions'][$fk] = $masterModelIds;
  150. }
  151. $otherModelIds = array_unique(Set::extract('{n}.' . $pk, $data));
  152. $this->_addCondition($Model, 'belongsTo', $modelName, $pk, $otherModelIds);
  153. }
  154. }
  155. /**
  156. * Make sub finds to hasMany assoc
  157. *
  158. * @access protected
  159. * @return void
  160. */
  161. function _subFindHasMany($data, &$Model, &$query) {
  162. foreach ($data as $modelName => $extraConditions) {
  163. $fk = $Model->hasMany[$modelName]['foreignKey'];
  164. $pk = $modelName . '.' . $Model->$modelName->primaryKey;
  165. $removeBehavior = false;
  166. if (!$Model->$modelName->Behaviors->attached('SuperFind')) {
  167. $removeBehavior = true;
  168. $Model->$modelName->Behaviors->attach('SuperFind.SuperFind');
  169. }
  170. $data = $Model->$modelName->superFind('all', array(
  171. 'fields' => array($fk, $pk),
  172. 'conditions' => $extraConditions,
  173. 'recursive' => -1
  174. ));
  175. if ($removeBehavior) {
  176. $Model->$modelName->Behaviors->detach('SuperFind.SuperFind');
  177. }
  178. $masterModelIds = array_unique(Set::extract('{n}.' . $modelName . '.' . $fk, $data));
  179. if (empty($masterModelIds)) {
  180. $query['conditions'] = '1 = 0';
  181. break;
  182. }
  183. $selfPk = $Model->alias . '.' . $Model->primaryKey;
  184. if (isset($query['conditions'][$selfPk])) {
  185. $query['conditions'][$selfPk] = array_intersect((array)$query['conditions'][$selfPk], $masterModelIds);
  186. } else {
  187. $query['conditions'][$selfPk] = $masterModelIds;
  188. }
  189. $otherModelIds = array_unique(Set::extract('{n}.' . $pk, $data));
  190. $this->_addCondition($Model, 'hasMany', $modelName, $pk, $otherModelIds);
  191. }
  192. }
  193. /**
  194. * Make sub finds to hasAndBelongsToMany assoc
  195. *
  196. * @access protected
  197. * @return void
  198. */
  199. function _subFindHasAndBelongsToMany($data, &$Model, &$query) {
  200. foreach ($data as $modelName => $extraConditions) {
  201. $pk = $modelName . '.' . $Model->$modelName->primaryKey;
  202. $removeBehavior = false;
  203. if (!$Model->$modelName->Behaviors->attached('SuperFind')) {
  204. $removeBehavior = true;
  205. $Model->$modelName->Behaviors->attach('SuperFind.SuperFind');
  206. }
  207. $data = $Model->$modelName->superFind('all', array(
  208. 'fields' => array($pk),
  209. 'conditions' => $extraConditions,
  210. 'recursive' => -1
  211. ));
  212. if ($removeBehavior) {
  213. $Model->$modelName->Behaviors->detach('SuperFind.SuperFind');
  214. }
  215. if (empty($data)) {
  216. $query['conditions'] = '1 = 0';
  217. break;
  218. }
  219. $otherModelIds = array_unique(Set::extract('{n}.' . $pk, $data));
  220. $relationModel = new Model(array(
  221. 'table' => $Model->hasAndBelongsToMany[$modelName]['joinTable'],
  222. 'ds' => $Model->useDbConfig,
  223. 'name' => 'Relation'
  224. ));
  225. $relationModel->Behaviors->attach('SuperFind.SuperFind');
  226. $data = $relationModel->superFind('all', array(
  227. 'fields' => array($Model->hasAndBelongsToMany[$modelName]['foreignKey']),
  228. 'conditions' => array($Model->hasAndBelongsToMany[$modelName]['associationForeignKey'] => $otherModelIds)
  229. ));
  230. unset($relationModel);
  231. if (empty($data)) {
  232. $query['conditions'] = '1 = 0';
  233. break;
  234. }
  235. $masterModelIds = array_unique(Set::extract('{n}.Relation.' . $Model->hasAndBelongsToMany[$modelName]['foreignKey'], $data));
  236. $selfPk = $Model->alias . '.' . $Model->primaryKey;
  237. if (isset($query['conditions'][$selfPk])) {
  238. $query['conditions'][$selfPk] = array_intersect((array)$query['conditions'][$selfPk], $masterModelIds);
  239. } else {
  240. $query['conditions'][$selfPk] = $masterModelIds;
  241. }
  242. $this->_addCondition($Model, 'hasAndBelongsToMany', $modelName, $pk, $otherModelIds);
  243. }
  244. }
  245. /**
  246. * Add a conditions in model
  247. *
  248. * @access protected
  249. * @return void
  250. */
  251. function _addCondition(&$Model, $type, $otherModel, $field, $value) {
  252. $relation =& $Model->$type;
  253. if (!empty($relation[$otherModel]['conditions'])) {
  254. $relation[$otherModel]['conditions'] = array($relation[$otherModel]['conditions']);
  255. }
  256. if (isset($relation[$otherModel]['conditions'][$field])) {
  257. if (!is_array($relation[$otherModel]['conditions'][$field])) {
  258. $relation[$otherModel]['conditions'][$field] = array($relation[$otherModel]['conditions'][$field]);
  259. }
  260. } else {
  261. $relation[$otherModel]['conditions'][$field] = array();
  262. }
  263. $relation[$otherModel]['conditions'][$field] = array_merge($relation[$otherModel]['conditions'][$field], $value);
  264. }
  265. }
  266. ?>