EnumeratesValues.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. <?php
  2. namespace Illuminate\Support\Traits;
  3. use CachingIterator;
  4. use Closure;
  5. use Exception;
  6. use Illuminate\Contracts\Support\Arrayable;
  7. use Illuminate\Contracts\Support\Jsonable;
  8. use Illuminate\Support\Arr;
  9. use Illuminate\Support\Collection;
  10. use Illuminate\Support\Enumerable;
  11. use Illuminate\Support\HigherOrderCollectionProxy;
  12. use Illuminate\Support\HigherOrderWhenProxy;
  13. use JsonSerializable;
  14. use Symfony\Component\VarDumper\VarDumper;
  15. use Traversable;
  16. use UnexpectedValueException;
  17. use UnitEnum;
  18. /**
  19. * @property-read HigherOrderCollectionProxy $average
  20. * @property-read HigherOrderCollectionProxy $avg
  21. * @property-read HigherOrderCollectionProxy $contains
  22. * @property-read HigherOrderCollectionProxy $doesntContain
  23. * @property-read HigherOrderCollectionProxy $each
  24. * @property-read HigherOrderCollectionProxy $every
  25. * @property-read HigherOrderCollectionProxy $filter
  26. * @property-read HigherOrderCollectionProxy $first
  27. * @property-read HigherOrderCollectionProxy $flatMap
  28. * @property-read HigherOrderCollectionProxy $groupBy
  29. * @property-read HigherOrderCollectionProxy $keyBy
  30. * @property-read HigherOrderCollectionProxy $map
  31. * @property-read HigherOrderCollectionProxy $max
  32. * @property-read HigherOrderCollectionProxy $min
  33. * @property-read HigherOrderCollectionProxy $partition
  34. * @property-read HigherOrderCollectionProxy $reject
  35. * @property-read HigherOrderCollectionProxy $some
  36. * @property-read HigherOrderCollectionProxy $sortBy
  37. * @property-read HigherOrderCollectionProxy $sortByDesc
  38. * @property-read HigherOrderCollectionProxy $skipUntil
  39. * @property-read HigherOrderCollectionProxy $skipWhile
  40. * @property-read HigherOrderCollectionProxy $sum
  41. * @property-read HigherOrderCollectionProxy $takeUntil
  42. * @property-read HigherOrderCollectionProxy $takeWhile
  43. * @property-read HigherOrderCollectionProxy $unique
  44. * @property-read HigherOrderCollectionProxy $until
  45. */
  46. trait EnumeratesValues
  47. {
  48. /**
  49. * Indicates that the object's string representation should be escaped when __toString is invoked.
  50. *
  51. * @var bool
  52. */
  53. protected $escapeWhenCastingToString = false;
  54. /**
  55. * The methods that can be proxied.
  56. *
  57. * @var string[]
  58. */
  59. protected static $proxies = [
  60. 'average',
  61. 'avg',
  62. 'contains',
  63. 'doesntContain',
  64. 'each',
  65. 'every',
  66. 'filter',
  67. 'first',
  68. 'flatMap',
  69. 'groupBy',
  70. 'keyBy',
  71. 'map',
  72. 'max',
  73. 'min',
  74. 'partition',
  75. 'reject',
  76. 'skipUntil',
  77. 'skipWhile',
  78. 'some',
  79. 'sortBy',
  80. 'sortByDesc',
  81. 'sum',
  82. 'takeUntil',
  83. 'takeWhile',
  84. 'unique',
  85. 'until',
  86. ];
  87. /**
  88. * Create a new collection instance if the value isn't one already.
  89. *
  90. * @param mixed $items
  91. * @return static
  92. */
  93. public static function make($items = [])
  94. {
  95. return new static($items);
  96. }
  97. /**
  98. * Wrap the given value in a collection if applicable.
  99. *
  100. * @param mixed $value
  101. * @return static
  102. */
  103. public static function wrap($value)
  104. {
  105. return $value instanceof Enumerable
  106. ? new static($value)
  107. : new static(Arr::wrap($value));
  108. }
  109. /**
  110. * Get the underlying items from the given collection if applicable.
  111. *
  112. * @param array|static $value
  113. * @return array
  114. */
  115. public static function unwrap($value)
  116. {
  117. return $value instanceof Enumerable ? $value->all() : $value;
  118. }
  119. /**
  120. * Create a new instance with no items.
  121. *
  122. * @return static
  123. */
  124. public static function empty()
  125. {
  126. return new static([]);
  127. }
  128. /**
  129. * Create a new collection by invoking the callback a given amount of times.
  130. *
  131. * @param int $number
  132. * @param callable|null $callback
  133. * @return static
  134. */
  135. public static function times($number, callable $callback = null)
  136. {
  137. if ($number < 1) {
  138. return new static;
  139. }
  140. return static::range(1, $number)
  141. ->when($callback)
  142. ->map($callback);
  143. }
  144. /**
  145. * Alias for the "avg" method.
  146. *
  147. * @param callable|string|null $callback
  148. * @return mixed
  149. */
  150. public function average($callback = null)
  151. {
  152. return $this->avg($callback);
  153. }
  154. /**
  155. * Alias for the "contains" method.
  156. *
  157. * @param mixed $key
  158. * @param mixed $operator
  159. * @param mixed $value
  160. * @return bool
  161. */
  162. public function some($key, $operator = null, $value = null)
  163. {
  164. return $this->contains(...func_get_args());
  165. }
  166. /**
  167. * Determine if an item exists, using strict comparison.
  168. *
  169. * @param mixed $key
  170. * @param mixed $value
  171. * @return bool
  172. */
  173. public function containsStrict($key, $value = null)
  174. {
  175. if (func_num_args() === 2) {
  176. return $this->contains(function ($item) use ($key, $value) {
  177. return data_get($item, $key) === $value;
  178. });
  179. }
  180. if ($this->useAsCallable($key)) {
  181. return ! is_null($this->first($key));
  182. }
  183. foreach ($this as $item) {
  184. if ($item === $key) {
  185. return true;
  186. }
  187. }
  188. return false;
  189. }
  190. /**
  191. * Dump the items and end the script.
  192. *
  193. * @param mixed ...$args
  194. * @return void
  195. */
  196. public function dd(...$args)
  197. {
  198. $this->dump(...$args);
  199. exit(1);
  200. }
  201. /**
  202. * Dump the items.
  203. *
  204. * @return $this
  205. */
  206. public function dump()
  207. {
  208. (new Collection(func_get_args()))
  209. ->push($this->all())
  210. ->each(function ($item) {
  211. VarDumper::dump($item);
  212. });
  213. return $this;
  214. }
  215. /**
  216. * Execute a callback over each item.
  217. *
  218. * @param callable $callback
  219. * @return $this
  220. */
  221. public function each(callable $callback)
  222. {
  223. foreach ($this as $key => $item) {
  224. if ($callback($item, $key) === false) {
  225. break;
  226. }
  227. }
  228. return $this;
  229. }
  230. /**
  231. * Execute a callback over each nested chunk of items.
  232. *
  233. * @param callable $callback
  234. * @return static
  235. */
  236. public function eachSpread(callable $callback)
  237. {
  238. return $this->each(function ($chunk, $key) use ($callback) {
  239. $chunk[] = $key;
  240. return $callback(...$chunk);
  241. });
  242. }
  243. /**
  244. * Determine if all items pass the given truth test.
  245. *
  246. * @param string|callable $key
  247. * @param mixed $operator
  248. * @param mixed $value
  249. * @return bool
  250. */
  251. public function every($key, $operator = null, $value = null)
  252. {
  253. if (func_num_args() === 1) {
  254. $callback = $this->valueRetriever($key);
  255. foreach ($this as $k => $v) {
  256. if (! $callback($v, $k)) {
  257. return false;
  258. }
  259. }
  260. return true;
  261. }
  262. return $this->every($this->operatorForWhere(...func_get_args()));
  263. }
  264. /**
  265. * Get the first item by the given key value pair.
  266. *
  267. * @param string $key
  268. * @param mixed $operator
  269. * @param mixed $value
  270. * @return mixed
  271. */
  272. public function firstWhere($key, $operator = null, $value = null)
  273. {
  274. return $this->first($this->operatorForWhere(...func_get_args()));
  275. }
  276. /**
  277. * Determine if the collection is not empty.
  278. *
  279. * @return bool
  280. */
  281. public function isNotEmpty()
  282. {
  283. return ! $this->isEmpty();
  284. }
  285. /**
  286. * Run a map over each nested chunk of items.
  287. *
  288. * @param callable $callback
  289. * @return static
  290. */
  291. public function mapSpread(callable $callback)
  292. {
  293. return $this->map(function ($chunk, $key) use ($callback) {
  294. $chunk[] = $key;
  295. return $callback(...$chunk);
  296. });
  297. }
  298. /**
  299. * Run a grouping map over the items.
  300. *
  301. * The callback should return an associative array with a single key/value pair.
  302. *
  303. * @param callable $callback
  304. * @return static
  305. */
  306. public function mapToGroups(callable $callback)
  307. {
  308. $groups = $this->mapToDictionary($callback);
  309. return $groups->map([$this, 'make']);
  310. }
  311. /**
  312. * Map a collection and flatten the result by a single level.
  313. *
  314. * @param callable $callback
  315. * @return static
  316. */
  317. public function flatMap(callable $callback)
  318. {
  319. return $this->map($callback)->collapse();
  320. }
  321. /**
  322. * Map the values into a new class.
  323. *
  324. * @param string $class
  325. * @return static
  326. */
  327. public function mapInto($class)
  328. {
  329. return $this->map(function ($value, $key) use ($class) {
  330. return new $class($value, $key);
  331. });
  332. }
  333. /**
  334. * Get the min value of a given key.
  335. *
  336. * @param callable|string|null $callback
  337. * @return mixed
  338. */
  339. public function min($callback = null)
  340. {
  341. $callback = $this->valueRetriever($callback);
  342. return $this->map(function ($value) use ($callback) {
  343. return $callback($value);
  344. })->filter(function ($value) {
  345. return ! is_null($value);
  346. })->reduce(function ($result, $value) {
  347. return is_null($result) || $value < $result ? $value : $result;
  348. });
  349. }
  350. /**
  351. * Get the max value of a given key.
  352. *
  353. * @param callable|string|null $callback
  354. * @return mixed
  355. */
  356. public function max($callback = null)
  357. {
  358. $callback = $this->valueRetriever($callback);
  359. return $this->filter(function ($value) {
  360. return ! is_null($value);
  361. })->reduce(function ($result, $item) use ($callback) {
  362. $value = $callback($item);
  363. return is_null($result) || $value > $result ? $value : $result;
  364. });
  365. }
  366. /**
  367. * "Paginate" the collection by slicing it into a smaller collection.
  368. *
  369. * @param int $page
  370. * @param int $perPage
  371. * @return static
  372. */
  373. public function forPage($page, $perPage)
  374. {
  375. $offset = max(0, ($page - 1) * $perPage);
  376. return $this->slice($offset, $perPage);
  377. }
  378. /**
  379. * Partition the collection into two arrays using the given callback or key.
  380. *
  381. * @param callable|string $key
  382. * @param mixed $operator
  383. * @param mixed $value
  384. * @return static
  385. */
  386. public function partition($key, $operator = null, $value = null)
  387. {
  388. $passed = [];
  389. $failed = [];
  390. $callback = func_num_args() === 1
  391. ? $this->valueRetriever($key)
  392. : $this->operatorForWhere(...func_get_args());
  393. foreach ($this as $key => $item) {
  394. if ($callback($item, $key)) {
  395. $passed[$key] = $item;
  396. } else {
  397. $failed[$key] = $item;
  398. }
  399. }
  400. return new static([new static($passed), new static($failed)]);
  401. }
  402. /**
  403. * Get the sum of the given values.
  404. *
  405. * @param callable|string|null $callback
  406. * @return mixed
  407. */
  408. public function sum($callback = null)
  409. {
  410. $callback = is_null($callback)
  411. ? $this->identity()
  412. : $this->valueRetriever($callback);
  413. return $this->reduce(function ($result, $item) use ($callback) {
  414. return $result + $callback($item);
  415. }, 0);
  416. }
  417. /**
  418. * Apply the callback if the value is truthy.
  419. *
  420. * @param bool|mixed $value
  421. * @param callable|null $callback
  422. * @param callable|null $default
  423. * @return static|mixed
  424. */
  425. public function when($value, callable $callback = null, callable $default = null)
  426. {
  427. if (! $callback) {
  428. return new HigherOrderWhenProxy($this, $value);
  429. }
  430. if ($value) {
  431. return $callback($this, $value);
  432. } elseif ($default) {
  433. return $default($this, $value);
  434. }
  435. return $this;
  436. }
  437. /**
  438. * Apply the callback if the collection is empty.
  439. *
  440. * @param callable $callback
  441. * @param callable|null $default
  442. * @return static|mixed
  443. */
  444. public function whenEmpty(callable $callback, callable $default = null)
  445. {
  446. return $this->when($this->isEmpty(), $callback, $default);
  447. }
  448. /**
  449. * Apply the callback if the collection is not empty.
  450. *
  451. * @param callable $callback
  452. * @param callable|null $default
  453. * @return static|mixed
  454. */
  455. public function whenNotEmpty(callable $callback, callable $default = null)
  456. {
  457. return $this->when($this->isNotEmpty(), $callback, $default);
  458. }
  459. /**
  460. * Apply the callback if the value is falsy.
  461. *
  462. * @param bool $value
  463. * @param callable $callback
  464. * @param callable|null $default
  465. * @return static|mixed
  466. */
  467. public function unless($value, callable $callback, callable $default = null)
  468. {
  469. return $this->when(! $value, $callback, $default);
  470. }
  471. /**
  472. * Apply the callback unless the collection is empty.
  473. *
  474. * @param callable $callback
  475. * @param callable|null $default
  476. * @return static|mixed
  477. */
  478. public function unlessEmpty(callable $callback, callable $default = null)
  479. {
  480. return $this->whenNotEmpty($callback, $default);
  481. }
  482. /**
  483. * Apply the callback unless the collection is not empty.
  484. *
  485. * @param callable $callback
  486. * @param callable|null $default
  487. * @return static|mixed
  488. */
  489. public function unlessNotEmpty(callable $callback, callable $default = null)
  490. {
  491. return $this->whenEmpty($callback, $default);
  492. }
  493. /**
  494. * Filter items by the given key value pair.
  495. *
  496. * @param string $key
  497. * @param mixed $operator
  498. * @param mixed $value
  499. * @return static
  500. */
  501. public function where($key, $operator = null, $value = null)
  502. {
  503. return $this->filter($this->operatorForWhere(...func_get_args()));
  504. }
  505. /**
  506. * Filter items where the value for the given key is null.
  507. *
  508. * @param string|null $key
  509. * @return static
  510. */
  511. public function whereNull($key = null)
  512. {
  513. return $this->whereStrict($key, null);
  514. }
  515. /**
  516. * Filter items where the value for the given key is not null.
  517. *
  518. * @param string|null $key
  519. * @return static
  520. */
  521. public function whereNotNull($key = null)
  522. {
  523. return $this->where($key, '!==', null);
  524. }
  525. /**
  526. * Filter items by the given key value pair using strict comparison.
  527. *
  528. * @param string $key
  529. * @param mixed $value
  530. * @return static
  531. */
  532. public function whereStrict($key, $value)
  533. {
  534. return $this->where($key, '===', $value);
  535. }
  536. /**
  537. * Filter items by the given key value pair.
  538. *
  539. * @param string $key
  540. * @param mixed $values
  541. * @param bool $strict
  542. * @return static
  543. */
  544. public function whereIn($key, $values, $strict = false)
  545. {
  546. $values = $this->getArrayableItems($values);
  547. return $this->filter(function ($item) use ($key, $values, $strict) {
  548. return in_array(data_get($item, $key), $values, $strict);
  549. });
  550. }
  551. /**
  552. * Filter items by the given key value pair using strict comparison.
  553. *
  554. * @param string $key
  555. * @param mixed $values
  556. * @return static
  557. */
  558. public function whereInStrict($key, $values)
  559. {
  560. return $this->whereIn($key, $values, true);
  561. }
  562. /**
  563. * Filter items such that the value of the given key is between the given values.
  564. *
  565. * @param string $key
  566. * @param array $values
  567. * @return static
  568. */
  569. public function whereBetween($key, $values)
  570. {
  571. return $this->where($key, '>=', reset($values))->where($key, '<=', end($values));
  572. }
  573. /**
  574. * Filter items such that the value of the given key is not between the given values.
  575. *
  576. * @param string $key
  577. * @param array $values
  578. * @return static
  579. */
  580. public function whereNotBetween($key, $values)
  581. {
  582. return $this->filter(function ($item) use ($key, $values) {
  583. return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values);
  584. });
  585. }
  586. /**
  587. * Filter items by the given key value pair.
  588. *
  589. * @param string $key
  590. * @param mixed $values
  591. * @param bool $strict
  592. * @return static
  593. */
  594. public function whereNotIn($key, $values, $strict = false)
  595. {
  596. $values = $this->getArrayableItems($values);
  597. return $this->reject(function ($item) use ($key, $values, $strict) {
  598. return in_array(data_get($item, $key), $values, $strict);
  599. });
  600. }
  601. /**
  602. * Filter items by the given key value pair using strict comparison.
  603. *
  604. * @param string $key
  605. * @param mixed $values
  606. * @return static
  607. */
  608. public function whereNotInStrict($key, $values)
  609. {
  610. return $this->whereNotIn($key, $values, true);
  611. }
  612. /**
  613. * Filter the items, removing any items that don't match the given type(s).
  614. *
  615. * @param string|string[] $type
  616. * @return static
  617. */
  618. public function whereInstanceOf($type)
  619. {
  620. return $this->filter(function ($value) use ($type) {
  621. if (is_array($type)) {
  622. foreach ($type as $classType) {
  623. if ($value instanceof $classType) {
  624. return true;
  625. }
  626. }
  627. return false;
  628. }
  629. return $value instanceof $type;
  630. });
  631. }
  632. /**
  633. * Pass the collection to the given callback and return the result.
  634. *
  635. * @param callable $callback
  636. * @return mixed
  637. */
  638. public function pipe(callable $callback)
  639. {
  640. return $callback($this);
  641. }
  642. /**
  643. * Pass the collection into a new class.
  644. *
  645. * @param string $class
  646. * @return mixed
  647. */
  648. public function pipeInto($class)
  649. {
  650. return new $class($this);
  651. }
  652. /**
  653. * Pass the collection through a series of callable pipes and return the result.
  654. *
  655. * @param array<callable> $pipes
  656. * @return mixed
  657. */
  658. public function pipeThrough($pipes)
  659. {
  660. return static::make($pipes)->reduce(
  661. function ($carry, $pipe) {
  662. return $pipe($carry);
  663. },
  664. $this,
  665. );
  666. }
  667. /**
  668. * Pass the collection to the given callback and then return it.
  669. *
  670. * @param callable $callback
  671. * @return $this
  672. */
  673. public function tap(callable $callback)
  674. {
  675. $callback(clone $this);
  676. return $this;
  677. }
  678. /**
  679. * Reduce the collection to a single value.
  680. *
  681. * @param callable $callback
  682. * @param mixed $initial
  683. * @return mixed
  684. */
  685. public function reduce(callable $callback, $initial = null)
  686. {
  687. $result = $initial;
  688. foreach ($this as $key => $value) {
  689. $result = $callback($result, $value, $key);
  690. }
  691. return $result;
  692. }
  693. /**
  694. * Reduce the collection to multiple aggregate values.
  695. *
  696. * @param callable $callback
  697. * @param mixed ...$initial
  698. * @return array
  699. *
  700. * @deprecated Use "reduceSpread" instead
  701. *
  702. * @throws \UnexpectedValueException
  703. */
  704. public function reduceMany(callable $callback, ...$initial)
  705. {
  706. return $this->reduceSpread($callback, ...$initial);
  707. }
  708. /**
  709. * Reduce the collection to multiple aggregate values.
  710. *
  711. * @param callable $callback
  712. * @param mixed ...$initial
  713. * @return array
  714. *
  715. * @throws \UnexpectedValueException
  716. */
  717. public function reduceSpread(callable $callback, ...$initial)
  718. {
  719. $result = $initial;
  720. foreach ($this as $key => $value) {
  721. $result = call_user_func_array($callback, array_merge($result, [$value, $key]));
  722. if (! is_array($result)) {
  723. throw new UnexpectedValueException(sprintf(
  724. "%s::reduceMany expects reducer to return an array, but got a '%s' instead.",
  725. class_basename(static::class), gettype($result)
  726. ));
  727. }
  728. }
  729. return $result;
  730. }
  731. /**
  732. * Reduce an associative collection to a single value.
  733. *
  734. * @param callable $callback
  735. * @param mixed $initial
  736. * @return mixed
  737. */
  738. public function reduceWithKeys(callable $callback, $initial = null)
  739. {
  740. return $this->reduce($callback, $initial);
  741. }
  742. /**
  743. * Create a collection of all elements that do not pass a given truth test.
  744. *
  745. * @param callable|mixed $callback
  746. * @return static
  747. */
  748. public function reject($callback = true)
  749. {
  750. $useAsCallable = $this->useAsCallable($callback);
  751. return $this->filter(function ($value, $key) use ($callback, $useAsCallable) {
  752. return $useAsCallable
  753. ? ! $callback($value, $key)
  754. : $value != $callback;
  755. });
  756. }
  757. /**
  758. * Return only unique items from the collection array using strict comparison.
  759. *
  760. * @param string|callable|null $key
  761. * @return static
  762. */
  763. public function uniqueStrict($key = null)
  764. {
  765. return $this->unique($key, true);
  766. }
  767. /**
  768. * Collect the values into a collection.
  769. *
  770. * @return \Illuminate\Support\Collection
  771. */
  772. public function collect()
  773. {
  774. return new Collection($this->all());
  775. }
  776. /**
  777. * Get the collection of items as a plain array.
  778. *
  779. * @return array
  780. */
  781. public function toArray()
  782. {
  783. return $this->map(function ($value) {
  784. return $value instanceof Arrayable ? $value->toArray() : $value;
  785. })->all();
  786. }
  787. /**
  788. * Convert the object into something JSON serializable.
  789. *
  790. * @return array
  791. */
  792. #[\ReturnTypeWillChange]
  793. public function jsonSerialize()
  794. {
  795. return array_map(function ($value) {
  796. if ($value instanceof JsonSerializable) {
  797. return $value->jsonSerialize();
  798. } elseif ($value instanceof Jsonable) {
  799. return json_decode($value->toJson(), true);
  800. } elseif ($value instanceof Arrayable) {
  801. return $value->toArray();
  802. }
  803. return $value;
  804. }, $this->all());
  805. }
  806. /**
  807. * Get the collection of items as JSON.
  808. *
  809. * @param int $options
  810. * @return string
  811. */
  812. public function toJson($options = 0)
  813. {
  814. return json_encode($this->jsonSerialize(), $options);
  815. }
  816. /**
  817. * Get a CachingIterator instance.
  818. *
  819. * @param int $flags
  820. * @return \CachingIterator
  821. */
  822. public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
  823. {
  824. return new CachingIterator($this->getIterator(), $flags);
  825. }
  826. /**
  827. * Convert the collection to its string representation.
  828. *
  829. * @return string
  830. */
  831. public function __toString()
  832. {
  833. return $this->escapeWhenCastingToString
  834. ? e($this->toJson())
  835. : $this->toJson();
  836. }
  837. /**
  838. * Indicate that the model's string representation should be escaped when __toString is invoked.
  839. *
  840. * @param bool $escape
  841. * @return $this
  842. */
  843. public function escapeWhenCastingToString($escape = true)
  844. {
  845. $this->escapeWhenCastingToString = $escape;
  846. return $this;
  847. }
  848. /**
  849. * Add a method to the list of proxied methods.
  850. *
  851. * @param string $method
  852. * @return void
  853. */
  854. public static function proxy($method)
  855. {
  856. static::$proxies[] = $method;
  857. }
  858. /**
  859. * Dynamically access collection proxies.
  860. *
  861. * @param string $key
  862. * @return mixed
  863. *
  864. * @throws \Exception
  865. */
  866. public function __get($key)
  867. {
  868. if (! in_array($key, static::$proxies)) {
  869. throw new Exception("Property [{$key}] does not exist on this collection instance.");
  870. }
  871. return new HigherOrderCollectionProxy($this, $key);
  872. }
  873. /**
  874. * Results array of items from Collection or Arrayable.
  875. *
  876. * @param mixed $items
  877. * @return array
  878. */
  879. protected function getArrayableItems($items)
  880. {
  881. if (is_array($items)) {
  882. return $items;
  883. } elseif ($items instanceof Enumerable) {
  884. return $items->all();
  885. } elseif ($items instanceof Arrayable) {
  886. return $items->toArray();
  887. } elseif ($items instanceof Jsonable) {
  888. return json_decode($items->toJson(), true);
  889. } elseif ($items instanceof JsonSerializable) {
  890. return (array) $items->jsonSerialize();
  891. } elseif ($items instanceof Traversable) {
  892. return iterator_to_array($items);
  893. } elseif ($items instanceof UnitEnum) {
  894. return [$items];
  895. }
  896. return (array) $items;
  897. }
  898. /**
  899. * Get an operator checker callback.
  900. *
  901. * @param string $key
  902. * @param string|null $operator
  903. * @param mixed $value
  904. * @return \Closure
  905. */
  906. protected function operatorForWhere($key, $operator = null, $value = null)
  907. {
  908. if (func_num_args() === 1) {
  909. $value = true;
  910. $operator = '=';
  911. }
  912. if (func_num_args() === 2) {
  913. $value = $operator;
  914. $operator = '=';
  915. }
  916. return function ($item) use ($key, $operator, $value) {
  917. $retrieved = data_get($item, $key);
  918. $strings = array_filter([$retrieved, $value], function ($value) {
  919. return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
  920. });
  921. if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {
  922. return in_array($operator, ['!=', '<>', '!==']);
  923. }
  924. switch ($operator) {
  925. default:
  926. case '=':
  927. case '==': return $retrieved == $value;
  928. case '!=':
  929. case '<>': return $retrieved != $value;
  930. case '<': return $retrieved < $value;
  931. case '>': return $retrieved > $value;
  932. case '<=': return $retrieved <= $value;
  933. case '>=': return $retrieved >= $value;
  934. case '===': return $retrieved === $value;
  935. case '!==': return $retrieved !== $value;
  936. }
  937. };
  938. }
  939. /**
  940. * Determine if the given value is callable, but not a string.
  941. *
  942. * @param mixed $value
  943. * @return bool
  944. */
  945. protected function useAsCallable($value)
  946. {
  947. return ! is_string($value) && is_callable($value);
  948. }
  949. /**
  950. * Get a value retrieving callback.
  951. *
  952. * @param callable|string|null $value
  953. * @return callable
  954. */
  955. protected function valueRetriever($value)
  956. {
  957. if ($this->useAsCallable($value)) {
  958. return $value;
  959. }
  960. return function ($item) use ($value) {
  961. return data_get($item, $value);
  962. };
  963. }
  964. /**
  965. * Make a function to check an item's equality.
  966. *
  967. * @param mixed $value
  968. * @return \Closure
  969. */
  970. protected function equality($value)
  971. {
  972. return function ($item) use ($value) {
  973. return $item === $value;
  974. };
  975. }
  976. /**
  977. * Make a function using another function, by negating its result.
  978. *
  979. * @param \Closure $callback
  980. * @return \Closure
  981. */
  982. protected function negate(Closure $callback)
  983. {
  984. return function (...$params) use ($callback) {
  985. return ! $callback(...$params);
  986. };
  987. }
  988. /**
  989. * Make a function that returns what's passed to it.
  990. *
  991. * @return \Closure
  992. */
  993. protected function identity()
  994. {
  995. return function ($value) {
  996. return $value;
  997. };
  998. }
  999. }