PluginProbe
Independent Analytics – WordPress Analytics Plugin / 2.9.2
Independent Analytics – WordPress Analytics Plugin v2.9.2
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 All 120 releases
independent-analytics / vendor / illuminate / database / Concerns / BuildsQueries.php
BuildsQueries.php
395 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace IAWPSCOPED\Illuminate\Database\Concerns;
4
5 use IAWPSCOPED\Illuminate\Container\Container;
6 use IAWPSCOPED\Illuminate\Database\Eloquent\Builder;
7 use IAWPSCOPED\Illuminate\Database\MultipleRecordsFoundException;
8 use IAWPSCOPED\Illuminate\Database\RecordsNotFoundException;
9 use IAWPSCOPED\Illuminate\Pagination\Cursor;
10 use IAWPSCOPED\Illuminate\Pagination\CursorPaginator;
11 use IAWPSCOPED\Illuminate\Pagination\LengthAwarePaginator;
12 use IAWPSCOPED\Illuminate\Pagination\Paginator;
13 use IAWPSCOPED\Illuminate\Support\Collection;
14 use IAWPSCOPED\Illuminate\Support\LazyCollection;
15 use IAWPSCOPED\Illuminate\Support\Traits\Conditionable;
16 use InvalidArgumentException;
17 use RuntimeException;
18 /** @internal */
19 trait BuildsQueries
20 {
21 use Conditionable;
22 /**
23 * Chunk the results of the query.
24 *
25 * @param int $count
26 * @param callable $callback
27 * @return bool
28 */
29 public function chunk($count, callable $callback)
30 {
31 $this->enforceOrderBy();
32 $page = 1;
33 do {
34 // We'll execute the query for the given page and get the results. If there are
35 // no results we can just break and return from here. When there are results
36 // we will call the callback with the current chunk of these results here.
37 $results = $this->forPage($page, $count)->get();
38 $countResults = $results->count();
39 if ($countResults == 0) {
40 break;
41 }
42 // On each chunk result set, we will pass them to the callback and then let the
43 // developer take care of everything within the callback, which allows us to
44 // keep the memory low for spinning through large result sets for working.
45 if ($callback($results, $page) === \false) {
46 return \false;
47 }
48 unset($results);
49 $page++;
50 } while ($countResults == $count);
51 return \true;
52 }
53 /**
54 * Run a map over each item while chunking.
55 *
56 * @param callable $callback
57 * @param int $count
58 * @return \Illuminate\Support\Collection
59 */
60 public function chunkMap(callable $callback, $count = 1000)
61 {
62 $collection = Collection::make();
63 $this->chunk($count, function ($items) use($collection, $callback) {
64 $items->each(function ($item) use($collection, $callback) {
65 $collection->push($callback($item));
66 });
67 });
68 return $collection;
69 }
70 /**
71 * Execute a callback over each item while chunking.
72 *
73 * @param callable $callback
74 * @param int $count
75 * @return bool
76 *
77 * @throws \RuntimeException
78 */
79 public function each(callable $callback, $count = 1000)
80 {
81 return $this->chunk($count, function ($results) use($callback) {
82 foreach ($results as $key => $value) {
83 if ($callback($value, $key) === \false) {
84 return \false;
85 }
86 }
87 });
88 }
89 /**
90 * Chunk the results of a query by comparing IDs.
91 *
92 * @param int $count
93 * @param callable $callback
94 * @param string|null $column
95 * @param string|null $alias
96 * @return bool
97 */
98 public function chunkById($count, callable $callback, $column = null, $alias = null)
99 {
100 $column = $column ?? $this->defaultKeyName();
101 $alias = $alias ?? $column;
102 $lastId = null;
103 $page = 1;
104 do {
105 $clone = clone $this;
106 // We'll execute the query for the given page and get the results. If there are
107 // no results we can just break and return from here. When there are results
108 // we will call the callback with the current chunk of these results here.
109 $results = $clone->forPageAfterId($count, $lastId, $column)->get();
110 $countResults = $results->count();
111 if ($countResults == 0) {
112 break;
113 }
114 // On each chunk result set, we will pass them to the callback and then let the
115 // developer take care of everything within the callback, which allows us to
116 // keep the memory low for spinning through large result sets for working.
117 if ($callback($results, $page) === \false) {
118 return \false;
119 }
120 $lastId = $results->last()->{$alias};
121 if ($lastId === null) {
122 throw new RuntimeException("The chunkById operation was aborted because the [{$alias}] column is not present in the query result.");
123 }
124 unset($results);
125 $page++;
126 } while ($countResults == $count);
127 return \true;
128 }
129 /**
130 * Execute a callback over each item while chunking by ID.
131 *
132 * @param callable $callback
133 * @param int $count
134 * @param string|null $column
135 * @param string|null $alias
136 * @return bool
137 */
138 public function eachById(callable $callback, $count = 1000, $column = null, $alias = null)
139 {
140 return $this->chunkById($count, function ($results, $page) use($callback, $count) {
141 foreach ($results as $key => $value) {
142 if ($callback($value, ($page - 1) * $count + $key) === \false) {
143 return \false;
144 }
145 }
146 }, $column, $alias);
147 }
148 /**
149 * Query lazily, by chunks of the given size.
150 *
151 * @param int $chunkSize
152 * @return \Illuminate\Support\LazyCollection
153 *
154 * @throws \InvalidArgumentException
155 */
156 public function lazy($chunkSize = 1000)
157 {
158 if ($chunkSize < 1) {
159 throw new InvalidArgumentException('The chunk size should be at least 1');
160 }
161 $this->enforceOrderBy();
162 return LazyCollection::make(function () use($chunkSize) {
163 $page = 1;
164 while (\true) {
165 $results = $this->forPage($page++, $chunkSize)->get();
166 foreach ($results as $result) {
167 (yield $result);
168 }
169 if ($results->count() < $chunkSize) {
170 return;
171 }
172 }
173 });
174 }
175 /**
176 * Query lazily, by chunking the results of a query by comparing IDs.
177 *
178 * @param int $chunkSize
179 * @param string|null $column
180 * @param string|null $alias
181 * @return \Illuminate\Support\LazyCollection
182 *
183 * @throws \InvalidArgumentException
184 */
185 public function lazyById($chunkSize = 1000, $column = null, $alias = null)
186 {
187 return $this->orderedLazyById($chunkSize, $column, $alias);
188 }
189 /**
190 * Query lazily, by chunking the results of a query by comparing IDs in descending order.
191 *
192 * @param int $chunkSize
193 * @param string|null $column
194 * @param string|null $alias
195 * @return \Illuminate\Support\LazyCollection
196 *
197 * @throws \InvalidArgumentException
198 */
199 public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)
200 {
201 return $this->orderedLazyById($chunkSize, $column, $alias, \true);
202 }
203 /**
204 * Query lazily, by chunking the results of a query by comparing IDs in a given order.
205 *
206 * @param int $chunkSize
207 * @param string|null $column
208 * @param string|null $alias
209 * @param bool $descending
210 * @return \Illuminate\Support\LazyCollection
211 *
212 * @throws \InvalidArgumentException
213 */
214 protected function orderedLazyById($chunkSize = 1000, $column = null, $alias = null, $descending = \false)
215 {
216 if ($chunkSize < 1) {
217 throw new InvalidArgumentException('The chunk size should be at least 1');
218 }
219 $column = $column ?? $this->defaultKeyName();
220 $alias = $alias ?? $column;
221 return LazyCollection::make(function () use($chunkSize, $column, $alias, $descending) {
222 $lastId = null;
223 while (\true) {
224 $clone = clone $this;
225 if ($descending) {
226 $results = $clone->forPageBeforeId($chunkSize, $lastId, $column)->get();
227 } else {
228 $results = $clone->forPageAfterId($chunkSize, $lastId, $column)->get();
229 }
230 foreach ($results as $result) {
231 (yield $result);
232 }
233 if ($results->count() < $chunkSize) {
234 return;
235 }
236 $lastId = $results->last()->{$alias};
237 }
238 });
239 }
240 /**
241 * Execute the query and get the first result.
242 *
243 * @param array|string $columns
244 * @return \Illuminate\Database\Eloquent\Model|object|static|null
245 */
246 public function first($columns = ['*'])
247 {
248 return $this->take(1)->get($columns)->first();
249 }
250 /**
251 * Execute the query and get the first result if it's the sole matching record.
252 *
253 * @param array|string $columns
254 * @return \Illuminate\Database\Eloquent\Model|object|static|null
255 *
256 * @throws \Illuminate\Database\RecordsNotFoundException
257 * @throws \Illuminate\Database\MultipleRecordsFoundException
258 */
259 public function sole($columns = ['*'])
260 {
261 $result = $this->take(2)->get($columns);
262 if ($result->isEmpty()) {
263 throw new RecordsNotFoundException();
264 }
265 if ($result->count() > 1) {
266 throw new MultipleRecordsFoundException();
267 }
268 return $result->first();
269 }
270 /**
271 * Paginate the given query using a cursor paginator.
272 *
273 * @param int $perPage
274 * @param array $columns
275 * @param string $cursorName
276 * @param \Illuminate\Pagination\Cursor|string|null $cursor
277 * @return \Illuminate\Contracts\Pagination\CursorPaginator
278 */
279 protected function paginateUsingCursor($perPage, $columns = ['*'], $cursorName = 'cursor', $cursor = null)
280 {
281 if (!$cursor instanceof Cursor) {
282 $cursor = \is_string($cursor) ? Cursor::fromEncoded($cursor) : CursorPaginator::resolveCurrentCursor($cursorName, $cursor);
283 }
284 $orders = $this->ensureOrderForCursorPagination(!\is_null($cursor) && $cursor->pointsToPreviousItems());
285 if (!\is_null($cursor)) {
286 $addCursorConditions = function (self $builder, $previousColumn, $i) use(&$addCursorConditions, $cursor, $orders) {
287 $unionBuilders = isset($builder->unions) ? \IAWPSCOPED\collect($builder->unions)->pluck('query') : \IAWPSCOPED\collect();
288 if (!\is_null($previousColumn)) {
289 $builder->where($this->getOriginalColumnNameForCursorPagination($this, $previousColumn), '=', $cursor->parameter($previousColumn));
290 $unionBuilders->each(function ($unionBuilder) use($previousColumn, $cursor) {
291 $unionBuilder->where($this->getOriginalColumnNameForCursorPagination($this, $previousColumn), '=', $cursor->parameter($previousColumn));
292 $this->addBinding($unionBuilder->getRawBindings()['where'], 'union');
293 });
294 }
295 $builder->where(function (self $builder) use($addCursorConditions, $cursor, $orders, $i, $unionBuilders) {
296 ['column' => $column, 'direction' => $direction] = $orders[$i];
297 $builder->where($this->getOriginalColumnNameForCursorPagination($this, $column), $direction === 'asc' ? '>' : '<', $cursor->parameter($column));
298 if ($i < $orders->count() - 1) {
299 $builder->orWhere(function (self $builder) use($addCursorConditions, $column, $i) {
300 $addCursorConditions($builder, $column, $i + 1);
301 });
302 }
303 $unionBuilders->each(function ($unionBuilder) use($column, $direction, $cursor, $i, $orders, $addCursorConditions) {
304 $unionBuilder->where(function ($unionBuilder) use($column, $direction, $cursor, $i, $orders, $addCursorConditions) {
305 $unionBuilder->where($this->getOriginalColumnNameForCursorPagination($this, $column), $direction === 'asc' ? '>' : '<', $cursor->parameter($column));
306 if ($i < $orders->count() - 1) {
307 $unionBuilder->orWhere(function (self $builder) use($addCursorConditions, $column, $i) {
308 $addCursorConditions($builder, $column, $i + 1);
309 });
310 }
311 $this->addBinding($unionBuilder->getRawBindings()['where'], 'union');
312 });
313 });
314 });
315 };
316 $addCursorConditions($this, null, 0);
317 }
318 $this->limit($perPage + 1);
319 return $this->cursorPaginator($this->get($columns), $perPage, $cursor, ['path' => Paginator::resolveCurrentPath(), 'cursorName' => $cursorName, 'parameters' => $orders->pluck('column')->toArray()]);
320 }
321 /**
322 * Get the original column name of the given column, without any aliasing.
323 *
324 * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder
325 * @param string $parameter
326 * @return string
327 */
328 protected function getOriginalColumnNameForCursorPagination($builder, string $parameter)
329 {
330 $columns = $builder instanceof Builder ? $builder->getQuery()->columns : $builder->columns;
331 if (!\is_null($columns)) {
332 foreach ($columns as $column) {
333 if (($position = \stripos($column, ' as ')) !== \false) {
334 $as = \substr($column, $position, 4);
335 [$original, $alias] = \explode($as, $column);
336 if ($parameter === $alias) {
337 return $original;
338 }
339 }
340 }
341 }
342 return $parameter;
343 }
344 /**
345 * Create a new length-aware paginator instance.
346 *
347 * @param \Illuminate\Support\Collection $items
348 * @param int $total
349 * @param int $perPage
350 * @param int $currentPage
351 * @param array $options
352 * @return \Illuminate\Pagination\LengthAwarePaginator
353 */
354 protected function paginator($items, $total, $perPage, $currentPage, $options)
355 {
356 return Container::getInstance()->makeWith(LengthAwarePaginator::class, \compact('items', 'total', 'perPage', 'currentPage', 'options'));
357 }
358 /**
359 * Create a new simple paginator instance.
360 *
361 * @param \Illuminate\Support\Collection $items
362 * @param int $perPage
363 * @param int $currentPage
364 * @param array $options
365 * @return \Illuminate\Pagination\Paginator
366 */
367 protected function simplePaginator($items, $perPage, $currentPage, $options)
368 {
369 return Container::getInstance()->makeWith(Paginator::class, \compact('items', 'perPage', 'currentPage', 'options'));
370 }
371 /**
372 * Create a new cursor paginator instance.
373 *
374 * @param \Illuminate\Support\Collection $items
375 * @param int $perPage
376 * @param \Illuminate\Pagination\Cursor $cursor
377 * @param array $options
378 * @return \Illuminate\Pagination\CursorPaginator
379 */
380 protected function cursorPaginator($items, $perPage, $cursor, $options)
381 {
382 return Container::getInstance()->makeWith(CursorPaginator::class, \compact('items', 'perPage', 'cursor', 'options'));
383 }
384 /**
385 * Pass the query to a given callback.
386 *
387 * @param callable $callback
388 * @return $this|mixed
389 */
390 public function tap($callback)
391 {
392 return $this->when(\true, $callback);
393 }
394 }
395