PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.1.0
Kirki – Freeform Page Builder, Website Builder & Customizer v6.1.0
6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / libraries / framework / Database / Query / Relations / HasOne.php
kirki / libraries / framework / Database / Query / Relations Last commit date
BelongsTo.php 3 weeks ago BelongsToMany.php 3 weeks ago HasMany.php 3 weeks ago HasOne.php 3 weeks ago Relation.php 3 weeks ago
HasOne.php
268 lines
1 <?php
2
3 /**
4 * Define a one-to-one relation between parent and related models.
5 * Constrains the related query to match a single record whose foreign key points to the parent's local key.
6 * Supports lazy and eager loading and matching results back to parent models.
7 *
8 * @package Framework
9 * @subpackage Database\Query\Relations
10 * @since 1.0.0
11 */
12 namespace Kirki\Framework\Database\Query\Relations;
13
14 \defined('ABSPATH') || exit;
15 use Kirki\Framework\Database\Query\Collection;
16 use Kirki\Framework\Database\Concerns\HasDictionary;
17 use Kirki\Framework\Database\Query\Model;
18 use Kirki\Framework\Database\Query\QueryBuilder;
19 use function Kirki\Framework\Polyfill\array_last;
20 class HasOne extends Relation
21 {
22 use HasDictionary;
23 /**
24 * The foreign key on the related model that references the parent model.
25 *
26 * @var string
27 *
28 * @since 1.0.0
29 */
30 protected $foreign_key;
31 /**
32 * The local key on the parent model that is referenced by the related model.
33 *
34 * @var string
35 *
36 * @since 1.0.0
37 */
38 protected $local_key;
39 /**
40 * Create a new has-one relation instance.
41 *
42 * Stores key names and applies base constraints for the relation so that
43 * subsequent queries target only the appropriate related record.
44 *
45 * @param Model $related The related model instance
46 * @param Model $parent The parent model instance
47 * @param mixed $foreign_key The related table's foreign key
48 * @param mixed $local_key The parent's local key
49 *
50 * @return void No return value
51 *
52 * @since 1.0.0
53 */
54 public function __construct(Model $related, Model $parent, $foreign_key, $local_key)
55 {
56 $this->foreign_key = $foreign_key;
57 $this->local_key = $local_key;
58 parent::__construct($related, $parent);
59 }
60 /**
61 * Apply base constraints using the parent's local key.
62 *
63 * When the parent has a local key value, the query is limited to rows
64 * whose foreign key matches that value to ensure only the related record
65 * is retrieved.
66 *
67 * @return void
68 *
69 * @since 1.0.0
70 */
71 public function add_constraints()
72 {
73 if (static::$constraints) {
74 $this->query->where($this->foreign_key, '=', $this->get_parent_key_value());
75 $this->query->where_not_null($this->foreign_key);
76 }
77 }
78 /**
79 * Get the aggregate query for the relation.
80 *
81 * @param QueryBuilder $query The query builder instance
82 * @param QueryBuilder $parent The parent query builder instance
83 * @param array $columns The columns to select
84 *
85 * @return QueryBuilder The aggregate query builder
86 *
87 * @since 1.0.0
88 */
89 public function get_relation_existence_query(QueryBuilder $query, QueryBuilder $parent, $columns = ['*'])
90 {
91 if ($query->from === $parent->from) {
92 return $this->get_relation_existence_query_for_self_relation($query, $parent, $columns);
93 }
94 return parent::get_relation_existence_query($query, $parent, $columns);
95 }
96 /**
97 * Get the aggregate query for the relation.
98 *
99 * @param QueryBuilder $query The query builder instance
100 * @param QueryBuilder $parent The parent query builder instance
101 * @param array $columns The columns to select
102 *
103 * @return QueryBuilder The aggregate query builder
104 *
105 * @since 1.0.0
106 */
107 public function get_relation_existence_query_for_self_relation(QueryBuilder $query, QueryBuilder $parent, $columns = ['*'])
108 {
109 $query->from($query->get_model()->get_table() . ' as ' . ($hash = $this->get_relation_count_hash()));
110 $query->get_model()->set_table($hash);
111 return $query->select($columns)->where_column($this->get_qualified_parent_key_name(), '=', $hash . '.' . $this->get_foreign_key_name());
112 }
113 /**
114 * Get the existence compare key for the relation.
115 *
116 * @return string The existence compare key
117 *
118 * @since 1.0.0
119 */
120 public function get_existence_compare_key()
121 {
122 return $this->qualify_column($this->foreign_key);
123 }
124 /**
125 * Get the qualified parent key name.
126 *
127 * @return string The qualified parent key name
128 *
129 * @since 1.0.0
130 */
131 public function get_qualified_parent_key_name()
132 {
133 return $this->parent->prepare_column($this->local_key);
134 }
135 /**
136 * Get the qualified foreign key name.
137 *
138 * @return string The qualified foreign key name
139 *
140 * @since 1.0.0
141 */
142 public function get_qualified_foreign_key_name()
143 {
144 return $this->foreign_key;
145 }
146 /**
147 * Get the foreign key name.
148 *
149 * @return string The foreign key name
150 *
151 * @since 1.0.0
152 */
153 public function get_foreign_key_name()
154 {
155 $segments = \explode('.', $this->get_qualified_foreign_key_name());
156 return array_last($segments);
157 }
158 /**
159 * Get the single related model for lazy loading.
160 *
161 * Returns the first result from the constrained query which should
162 * correspond to the one related record for the parent.
163 *
164 * @return mixed The related model instance or null if not found
165 *
166 * @since 1.0.0
167 */
168 public function get_results()
169 {
170 return !\is_null($this->get_parent_key_value()) ? $this->query->first() : null;
171 }
172 /**
173 * Get the parent key value.
174 *
175 * @return mixed The parent key value
176 *
177 * @since 1.0.0
178 */
179 protected function get_parent_key_value()
180 {
181 return $this->parent->get_attribute($this->local_key);
182 }
183 /**
184 * Add eager loading constraints across multiple parents.
185 *
186 * Collects parent local keys and scopes the query using a where_in to fetch
187 * all related records in a single query.
188 *
189 * @param Collection $models The array of parent models
190 *
191 * @return void
192 *
193 * @since 1.0.0
194 */
195 public function add_eager_constraints(Collection $models)
196 {
197 $this->where_in_eager($this->foreign_key, $this->get_keys($models, $this->local_key), $this->get_relation_query());
198 }
199 /**
200 * @inheritdoc
201 */
202 public function init_relation(Collection $models, $relation)
203 {
204 foreach ($models as $model) {
205 $model->set_relation($relation, null);
206 }
207 return $models;
208 }
209 /**
210 * Match eager loaded results back to their parents.
211 *
212 * Builds a dictionary keyed by the foreign key so that each parent can be
213 * assigned its corresponding related model instance.
214 *
215 * @param Collection $models The parent models to receive results
216 * @param mixed $results The related results to match
217 * @param string $relation The relation name on the parent
218 *
219 * @return array The array of parent models with relations set
220 *
221 * @since 1.0.0
222 */
223 public function match(Collection $models, $results, $relation)
224 {
225 $dictionary = $this->build_dictionary($results);
226 foreach ($models as $model) {
227 $attribute = $this->get_dictionary_key($model->get_attribute($this->local_key));
228 if ($attribute !== null && isset($dictionary[$attribute])) {
229 $model->set_relation($relation, $dictionary[$attribute]);
230 }
231 }
232 return $models;
233 }
234 /**
235 * Build the dictionary for the relation from the results.
236 *
237 * @param Collection $results The results.
238 *
239 * @return array The dictionary
240 *
241 * @since 1.0.0
242 */
243 protected function build_dictionary(Collection $results)
244 {
245 $dictionary = [];
246 foreach ($results as $result) {
247 $attribute = $this->get_dictionary_key($result->get_attribute($this->foreign_key));
248 if ($attribute !== null) {
249 $dictionary[$attribute] = $result;
250 }
251 }
252 return $dictionary;
253 }
254 /**
255 * Get the local key for the relation.
256 *
257 * Returns the key on the parent model that is used to match related records.
258 *
259 * @return string The local key name
260 *
261 * @since 1.0.0
262 */
263 public function get_local_key()
264 {
265 return $this->local_key;
266 }
267 }
268