PageRenderTime 33ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/hasone.php

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