PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.0.13
Kirki – Freeform Page Builder, Website Builder & Customizer v6.0.13
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 / EagerLoader.php
kirki / libraries / framework / Database / Query Last commit date
Relations 3 weeks ago Collection.php 3 weeks ago EagerLoader.php 3 weeks ago Expression.php 3 weeks ago JoinClause.php 3 weeks ago Model.php 3 weeks ago Paginator.php 3 weeks ago QueryBuilder.php 3 weeks ago QueryCompiler.php 3 weeks ago
EagerLoader.php
147 lines
1 <?php
2
3 /**
4 * Eager load one or more relations for a set of models.
5 * Accept an array of models and a list of relation method names,
6 * then fetch and match related records in as few queries as possible.
7 * This reduces N+1 query patterns by batching lookups and hydrating relation data onto the provided models.
8 *
9 * @package Framework
10 * @subpackage Database\Query
11 * @since 1.0.0
12 */
13 namespace Kirki\Framework\Database\Query;
14
15 \defined('ABSPATH') || exit;
16 use Closure;
17 use Kirki\Framework\Database\Query\Collection;
18 use Kirki\Framework\Database\Concerns\HasDictionary;
19 use Kirki\Framework\Database\Query\Relations\Relation;
20 use function Kirki\Framework\Polyfill\array_first;
21 class EagerLoader
22 {
23 use HasDictionary;
24 /**
25 * The array of model instances that will have their relations eagerly loaded.
26 *
27 * @var Collection
28 *
29 * @since 1.0.0
30 */
31 protected $models;
32 /**
33 * The list of relation method names to be eager loaded for the provided models.
34 *
35 * @var array
36 *
37 * @since 1.0.0
38 */
39 protected $relations;
40 /**
41 * Create a new eager loader instance.
42 *
43 * Stores the models and the requested relation names for later processing.
44 * Instances are typically constructed by the query builder when handling
45 * with() calls to prefetch related data efficiently.
46 *
47 * @param Collection $models The models that will receive related data
48 * @param array $relations The relation method names to eager load
49 *
50 * @return void No return value
51 *
52 * @since 1.0.0
53 */
54 public function __construct(Collection $models, array $relations)
55 {
56 $this->models = $models;
57 $this->relations = $relations;
58 }
59 /**
60 * Execute eager loading for all requested relations.
61 *
62 * Iterates over the configured relation names and invokes the loader for
63 * each. Returns the models array with relations populated on each model
64 * instance under their respective relation keys.
65 *
66 * @return array The array of models with loaded relations
67 *
68 * @since 1.0.0
69 */
70 public function load()
71 {
72 foreach ($this->relations as $relation_name => $nested_relations) {
73 $this->load_relation($relation_name, $nested_relations);
74 }
75 return $this->models;
76 }
77 /**
78 * Load a single relation across all provided models.
79 *
80 * Determines if the relation method exists, derives the relation object,
81 * applies eager constraints, fetches related results, and matches them to
82 * their parents. No operation occurs when models are empty or the method
83 * is missing.
84 *
85 * @param string $relation_name The relation method name to load
86 * @param mixed $nested_relations Nested relations to load on the related models
87 *
88 * @return void
89 *
90 * @since 1.0.0
91 */
92 protected function load_relation($relation_name, $nested_relations = null)
93 {
94 if ($this->models->empty()) {
95 return;
96 }
97 $first_model = $this->models->first();
98 if (!\method_exists($first_model, $relation_name)) {
99 return;
100 }
101 /**
102 * The relation instance.
103 *
104 * @var Relation
105 */
106 $relation = $first_model->{$relation_name}();
107 $relation->add_eager_constraints($this->models);
108 $callback = array_first($nested_relations);
109 if ($callback instanceof Closure) {
110 $callback($relation->get_query());
111 }
112 $results = $relation->get_eager();
113 $this->models = $relation->match($relation->init_relation($this->models, $relation_name), $results, $relation_name);
114 if (!empty($nested_relations) && !$results->empty() && !$callback instanceof Closure) {
115 $this->load_nested_relations($relation_name, $nested_relations);
116 }
117 }
118 /**
119 * Load nested relations on the related models.
120 *
121 * @param string $relation_name The parent relation name
122 * @param array $nested_relations The nested relations to load
123 *
124 * @return void
125 *
126 * @since 1.0.0
127 */
128 protected function load_nested_relations($relation_name, $nested_relations)
129 {
130 $related_models = new Collection();
131 foreach ($this->models as $model) {
132 if (!isset($model->relations[$relation_name])) {
133 continue;
134 }
135 $related = $model->relations[$relation_name];
136 if ($related instanceof Collection) {
137 $related_models = $related_models->merge($related);
138 } elseif (\is_object($related)) {
139 $related_models->push($related);
140 }
141 }
142 if (!empty($related_models)) {
143 (new static($related_models, $nested_relations))->load();
144 }
145 }
146 }
147