PageRenderTime 124ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/category_tool/fuel/packages/orm/classes/hasmany.php

https://github.com/connvoi/dev
PHP | 248 lines | 201 code | 25 blank | 22 comment | 19 complexity | 8de87b0878a89197fee43838cfbf02ee MD5 | raw file
Possible License(s): MIT, BSD-3-Clause
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2012 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Orm;
  13. class HasMany extends Relation
  14. {
  15. public function __construct($from, $name, array $config)
  16. {
  17. $this->name = $name;
  18. $this->model_from = $from;
  19. $this->model_to = array_key_exists('model_to', $config)
  20. ? $config['model_to'] : \Inflector::get_namespace($from).'Model_'.\Inflector::classify($name);
  21. $this->key_from = array_key_exists('key_from', $config)
  22. ? (array) $config['key_from'] : $this->key_from;
  23. $this->key_to = array_key_exists('key_to', $config)
  24. ? (array) $config['key_to'] : (array) \Inflector::foreign_key($this->model_from);
  25. $this->conditions = array_key_exists('conditions', $config)
  26. ? (array) $config['conditions'] : array();
  27. $this->cascade_save = array_key_exists('cascade_save', $config)
  28. ? $config['cascade_save'] : $this->cascade_save;
  29. $this->cascade_delete = array_key_exists('cascade_delete', $config)
  30. ? $config['cascade_delete'] : $this->cascade_delete;
  31. if ( ! class_exists($this->model_to))
  32. {
  33. throw new \FuelException('Related model not found by Has_Many relation "'.$this->name.'": '.$this->model_to);
  34. }
  35. $this->model_to = get_real_class($this->model_to);
  36. }
  37. public function get(Model $from)
  38. {
  39. $query = call_user_func(array($this->model_to, 'find'));
  40. reset($this->key_to);
  41. foreach ($this->key_from as $key)
  42. {
  43. $query->where(current($this->key_to), $from->{$key});
  44. next($this->key_to);
  45. }
  46. return $query->get();
  47. }
  48. public function join($alias_from, $rel_name, $alias_to_nr, $conditions = array())
  49. {
  50. $alias_to = 't'.$alias_to_nr;
  51. $model = array(
  52. 'model' => $this->model_to,
  53. 'connection' => call_user_func(array($this->model_to, 'connection')),
  54. 'table' => array(call_user_func(array($this->model_to, 'table')), $alias_to),
  55. 'primary_key' => call_user_func(array($this->model_to, 'primary_key')),
  56. 'join_type' => \Arr::get($conditions, 'join_type') ?: \Arr::get($this->conditions, 'join_type', 'left'),
  57. 'join_on' => array(),
  58. 'columns' => $this->select($alias_to),
  59. 'rel_name' => strpos($rel_name, '.') ? substr($rel_name, strrpos($rel_name, '.') + 1) : $rel_name,
  60. 'relation' => $this,
  61. 'where' => \Arr::get($conditions, 'where', array()),
  62. 'order_by' => \Arr::get($conditions, 'order_by') ?: \Arr::get($this->conditions, 'order_by', array()),
  63. );
  64. reset($this->key_to);
  65. foreach ($this->key_from as $key)
  66. {
  67. $model['join_on'][] = array($alias_from.'.'.$key, '=', $alias_to.'.'.current($this->key_to));
  68. next($this->key_to);
  69. }
  70. foreach (\Arr::get($this->conditions, 'where', array()) as $key => $condition)
  71. {
  72. ! is_array($condition) and $condition = array($key, '=', $condition);
  73. if ( ! $condition[0] instanceof \Fuel\Core\Database_Expression and strpos($condition[0], '.') === false)
  74. {
  75. $condition[0] = $alias_to.'.'.$condition[0];
  76. }
  77. is_string($condition[2]) and $condition[2] = \Db::quote($condition[2], $model['connection']);
  78. $model['join_on'][] = $condition;
  79. }
  80. return array($rel_name => $model);
  81. }
  82. public function save($model_from, $models_to, $original_model_ids, $parent_saved, $cascade)
  83. {
  84. if ( ! $parent_saved)
  85. {
  86. return;
  87. }
  88. if ( ! is_array($models_to) and ($models_to = is_null($models_to) ? array() : $models_to) !== array())
  89. {
  90. throw new \FuelException('Assigned relationships must be an array or null, given relationship value for '.
  91. $this->name.' is invalid.');
  92. }
  93. $original_model_ids === null and $original_model_ids = array();
  94. foreach ($models_to as $key => $model_to)
  95. {
  96. if ( ! $model_to instanceof $this->model_to)
  97. {
  98. throw new \FuelException('Invalid Model instance added to relations in this model.');
  99. }
  100. $current_model_id = ($model_to and ! $model_to->is_new()) ? $model_to->implode_pk($model_to) : null;
  101. // Check if the model was already assigned
  102. if (($model_to and $model_to->is_new()) or ! in_array($current_model_id, $original_model_ids))
  103. {
  104. // assign this object to the new objects foreign keys
  105. reset($this->key_to);
  106. $frozen = $model_to->frozen(); // only unfreeze/refreeze when it was frozen
  107. $frozen and $model_to->unfreeze();
  108. foreach ($this->key_from as $pk)
  109. {
  110. $model_to->{current($this->key_to)} = $model_from->{$pk};
  111. next($this->key_to);
  112. }
  113. $model_to->is_new() and $model_to->save(false);
  114. $frozen and $model_to->freeze();
  115. }
  116. // check if the model_to's foreign_keys match the model_from's primary keys
  117. else
  118. {
  119. // unset current model from from array
  120. unset($original_model_ids[array_search($current_model_id, $original_model_ids)]);
  121. // check if model_to still refers to this model_from
  122. $changed = false;
  123. reset($this->key_to);
  124. foreach ($this->key_from as $pk)
  125. {
  126. if ($model_to->{current($this->key_to)} != $model_from->{$pk})
  127. {
  128. $changed = true;
  129. }
  130. next($this->key_to);
  131. }
  132. // if any of the keys changed, the relationship was broken - remove model_to from loaded objects
  133. if ($changed)
  134. {
  135. $model_from->unfreeze();
  136. $rel = $model_from->_relate();
  137. unset($rel[$this->name][$key]);
  138. $model_from->_relate($rel);
  139. $model_from->freeze();
  140. // cascading this change won't work here, save just the object with cascading switched off
  141. $model_from->save(false);
  142. }
  143. }
  144. // Fix it if key isn't an imploded PK
  145. if ($key != ($current_model_id = $model_to->implode_pk($model_to)))
  146. {
  147. $model_from->unfreeze();
  148. $rel = $model_from->_relate();
  149. if ( ! empty($rel[$this->name][$key]) and $rel[$this->name][$key] === $model_to)
  150. {
  151. unset($rel[$this->name][$key]);
  152. }
  153. $rel[$this->name][$current_model_id] = $model_to;
  154. $model_from->_relate($rel);
  155. $model_from->freeze();
  156. }
  157. }
  158. // if any original ids are left over in the array, they're no longer related - break them
  159. foreach ($original_model_ids as $original_model_id)
  160. {
  161. // if still loaded set this object's old relation's foreign keys to null
  162. if ($original_model_id and $obj = call_user_func(array($this->model_to, 'find'),
  163. count($this->key_to) == 1 ? array($original_model_id) : explode('][', substr($original_model_id, 1, -1))))
  164. {
  165. $frozen = $obj->frozen(); // only unfreeze/refreeze when it was frozen
  166. $frozen and $obj->unfreeze();
  167. foreach ($this->key_to as $fk)
  168. {
  169. $obj->{$fk} = null;
  170. }
  171. $frozen and $obj->freeze();
  172. // cascading this change won't work here, save just the object with cascading switched off
  173. $obj->save(false);
  174. }
  175. }
  176. $cascade = is_null($cascade) ? $this->cascade_save : (bool) $cascade;
  177. if ($cascade and ! empty($models_to))
  178. {
  179. foreach ($models_to as $m)
  180. {
  181. $m->save();
  182. }
  183. }
  184. }
  185. public function delete($model_from, $models_to, $parent_deleted, $cascade)
  186. {
  187. if ( ! $parent_deleted)
  188. {
  189. return;
  190. }
  191. // break current relations
  192. $model_from->unfreeze();
  193. $rels = $model_from->_relate();
  194. $rels[$this->name] = array();
  195. $model_from->_relate($rels);
  196. $model_from->freeze();
  197. foreach ($models_to as $model_to)
  198. {
  199. if ( ! $model_to->frozen())
  200. {
  201. foreach ($this->key_to as $fk)
  202. {
  203. $model_to->{$fk} = null;
  204. }
  205. }
  206. }
  207. if ( ! empty($models_to))
  208. {
  209. $cascade = is_null($cascade) ? $this->cascade_delete : (bool) $cascade;
  210. foreach ($models_to as $m)
  211. {
  212. if ($cascade)
  213. {
  214. $m->delete();
  215. }
  216. else
  217. {
  218. $m->is_changed() and $m->save();
  219. }
  220. }
  221. }
  222. }
  223. }