CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • Collection

Interfaces

  • CollectionInterface

Traits

  • CollectionTrait
  • ExtractTrait
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   5:  *
   6:  * Licensed under The MIT License
   7:  * For full copyright and license information, please see the LICENSE.txt
   8:  * Redistributions of files must retain the above copyright notice.
   9:  *
  10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11:  * @link          https://cakephp.org CakePHP(tm) Project
  12:  * @since         3.0.0
  13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  14:  */
  15: namespace Cake\Collection;
  16: 
  17: use AppendIterator;
  18: use ArrayIterator;
  19: use Cake\Collection\Iterator\BufferedIterator;
  20: use Cake\Collection\Iterator\ExtractIterator;
  21: use Cake\Collection\Iterator\FilterIterator;
  22: use Cake\Collection\Iterator\InsertIterator;
  23: use Cake\Collection\Iterator\MapReduce;
  24: use Cake\Collection\Iterator\NestIterator;
  25: use Cake\Collection\Iterator\ReplaceIterator;
  26: use Cake\Collection\Iterator\SortIterator;
  27: use Cake\Collection\Iterator\StoppableIterator;
  28: use Cake\Collection\Iterator\TreeIterator;
  29: use Cake\Collection\Iterator\UnfoldIterator;
  30: use Cake\Collection\Iterator\ZipIterator;
  31: use Countable;
  32: use LimitIterator;
  33: use LogicException;
  34: use RecursiveIteratorIterator;
  35: use Traversable;
  36: 
  37: /**
  38:  * Offers a handful of methods to manipulate iterators
  39:  */
  40: trait CollectionTrait
  41: {
  42:     use ExtractTrait;
  43: 
  44:     /**
  45:      * Returns a new collection.
  46:      *
  47:      * Allows classes which use this trait to determine their own
  48:      * type of returned collection interface
  49:      *
  50:      * @param mixed ...$args Constructor arguments.
  51:      * @return \Cake\Collection\CollectionInterface
  52:      */
  53:     protected function newCollection(...$args)
  54:     {
  55:         return new Collection(...$args);
  56:     }
  57: 
  58:     /**
  59:      * {@inheritDoc}
  60:      */
  61:     public function each(callable $c)
  62:     {
  63:         foreach ($this->optimizeUnwrap() as $k => $v) {
  64:             $c($v, $k);
  65:         }
  66: 
  67:         return $this;
  68:     }
  69: 
  70:     /**
  71:      * {@inheritDoc}
  72:      *
  73:      * @return \Cake\Collection\Iterator\FilterIterator
  74:      */
  75:     public function filter(callable $c = null)
  76:     {
  77:         if ($c === null) {
  78:             $c = function ($v) {
  79:                 return (bool)$v;
  80:             };
  81:         }
  82: 
  83:         return new FilterIterator($this->unwrap(), $c);
  84:     }
  85: 
  86:     /**
  87:      * {@inheritDoc}
  88:      *
  89:      * @return \Cake\Collection\Iterator\FilterIterator
  90:      */
  91:     public function reject(callable $c)
  92:     {
  93:         return new FilterIterator($this->unwrap(), function ($key, $value, $items) use ($c) {
  94:             return !$c($key, $value, $items);
  95:         });
  96:     }
  97: 
  98:     /**
  99:      * {@inheritDoc}
 100:      */
 101:     public function every(callable $c)
 102:     {
 103:         foreach ($this->optimizeUnwrap() as $key => $value) {
 104:             if (!$c($value, $key)) {
 105:                 return false;
 106:             }
 107:         }
 108: 
 109:         return true;
 110:     }
 111: 
 112:     /**
 113:      * {@inheritDoc}
 114:      */
 115:     public function some(callable $c)
 116:     {
 117:         foreach ($this->optimizeUnwrap() as $key => $value) {
 118:             if ($c($value, $key) === true) {
 119:                 return true;
 120:             }
 121:         }
 122: 
 123:         return false;
 124:     }
 125: 
 126:     /**
 127:      * {@inheritDoc}
 128:      */
 129:     public function contains($value)
 130:     {
 131:         foreach ($this->optimizeUnwrap() as $v) {
 132:             if ($value === $v) {
 133:                 return true;
 134:             }
 135:         }
 136: 
 137:         return false;
 138:     }
 139: 
 140:     /**
 141:      * {@inheritDoc}
 142:      *
 143:      * @return \Cake\Collection\Iterator\ReplaceIterator
 144:      */
 145:     public function map(callable $c)
 146:     {
 147:         return new ReplaceIterator($this->unwrap(), $c);
 148:     }
 149: 
 150:     /**
 151:      * {@inheritDoc}
 152:      */
 153:     public function reduce(callable $c, $zero = null)
 154:     {
 155:         $isFirst = false;
 156:         if (func_num_args() < 2) {
 157:             $isFirst = true;
 158:         }
 159: 
 160:         $result = $zero;
 161:         foreach ($this->optimizeUnwrap() as $k => $value) {
 162:             if ($isFirst) {
 163:                 $result = $value;
 164:                 $isFirst = false;
 165:                 continue;
 166:             }
 167:             $result = $c($result, $value, $k);
 168:         }
 169: 
 170:         return $result;
 171:     }
 172: 
 173:     /**
 174:      * {@inheritDoc}
 175:      */
 176:     public function extract($matcher)
 177:     {
 178:         $extractor = new ExtractIterator($this->unwrap(), $matcher);
 179:         if (is_string($matcher) && strpos($matcher, '{*}') !== false) {
 180:             $extractor = $extractor
 181:                 ->filter(function ($data) {
 182:                     return $data !== null && ($data instanceof Traversable || is_array($data));
 183:                 })
 184:                 ->unfold();
 185:         }
 186: 
 187:         return $extractor;
 188:     }
 189: 
 190:     /**
 191:      * {@inheritDoc}
 192:      */
 193:     public function max($callback, $type = \SORT_NUMERIC)
 194:     {
 195:         return (new SortIterator($this->unwrap(), $callback, \SORT_DESC, $type))->first();
 196:     }
 197: 
 198:     /**
 199:      * {@inheritDoc}
 200:      */
 201:     public function min($callback, $type = \SORT_NUMERIC)
 202:     {
 203:         return (new SortIterator($this->unwrap(), $callback, \SORT_ASC, $type))->first();
 204:     }
 205: 
 206:     /**
 207:      * {@inheritDoc}
 208:      */
 209:     public function avg($matcher = null)
 210:     {
 211:         $result = $this;
 212:         if ($matcher != null) {
 213:             $result = $result->extract($matcher);
 214:         }
 215:         $result = $result
 216:             ->reduce(function ($acc, $current) {
 217:                 list($count, $sum) = $acc;
 218: 
 219:                 return [$count + 1, $sum + $current];
 220:             }, [0, 0]);
 221: 
 222:         if ($result[0] === 0) {
 223:             return null;
 224:         }
 225: 
 226:         return $result[1] / $result[0];
 227:     }
 228: 
 229:     /**
 230:      * {@inheritDoc}
 231:      */
 232:     public function median($matcher = null)
 233:     {
 234:         $elements = $this;
 235:         if ($matcher != null) {
 236:             $elements = $elements->extract($matcher);
 237:         }
 238:         $values = $elements->toList();
 239:         sort($values);
 240:         $count = count($values);
 241: 
 242:         if ($count === 0) {
 243:             return null;
 244:         }
 245: 
 246:         $middle = (int)($count / 2);
 247: 
 248:         if ($count % 2) {
 249:             return $values[$middle];
 250:         }
 251: 
 252:         return ($values[$middle - 1] + $values[$middle]) / 2;
 253:     }
 254: 
 255:     /**
 256:      * {@inheritDoc}
 257:      */
 258:     public function sortBy($callback, $dir = \SORT_DESC, $type = \SORT_NUMERIC)
 259:     {
 260:         return new SortIterator($this->unwrap(), $callback, $dir, $type);
 261:     }
 262: 
 263:     /**
 264:      * {@inheritDoc}
 265:      */
 266:     public function groupBy($callback)
 267:     {
 268:         $callback = $this->_propertyExtractor($callback);
 269:         $group = [];
 270:         foreach ($this->optimizeUnwrap() as $value) {
 271:             $group[$callback($value)][] = $value;
 272:         }
 273: 
 274:         return $this->newCollection($group);
 275:     }
 276: 
 277:     /**
 278:      * {@inheritDoc}
 279:      */
 280:     public function indexBy($callback)
 281:     {
 282:         $callback = $this->_propertyExtractor($callback);
 283:         $group = [];
 284:         foreach ($this->optimizeUnwrap() as $value) {
 285:             $group[$callback($value)] = $value;
 286:         }
 287: 
 288:         return $this->newCollection($group);
 289:     }
 290: 
 291:     /**
 292:      * {@inheritDoc}
 293:      */
 294:     public function countBy($callback)
 295:     {
 296:         $callback = $this->_propertyExtractor($callback);
 297: 
 298:         $mapper = function ($value, $key, $mr) use ($callback) {
 299:             /** @var \Cake\Collection\Iterator\MapReduce $mr */
 300:             $mr->emitIntermediate($value, $callback($value));
 301:         };
 302: 
 303:         $reducer = function ($values, $key, $mr) {
 304:             /** @var \Cake\Collection\Iterator\MapReduce $mr */
 305:             $mr->emit(count($values), $key);
 306:         };
 307: 
 308:         return $this->newCollection(new MapReduce($this->unwrap(), $mapper, $reducer));
 309:     }
 310: 
 311:     /**
 312:      * {@inheritDoc}
 313:      */
 314:     public function sumOf($matcher = null)
 315:     {
 316:         if ($matcher === null) {
 317:             return array_sum($this->toList());
 318:         }
 319: 
 320:         $callback = $this->_propertyExtractor($matcher);
 321:         $sum = 0;
 322:         foreach ($this->optimizeUnwrap() as $k => $v) {
 323:             $sum += $callback($v, $k);
 324:         }
 325: 
 326:         return $sum;
 327:     }
 328: 
 329:     /**
 330:      * {@inheritDoc}
 331:      */
 332:     public function shuffle()
 333:     {
 334:         $elements = $this->toArray();
 335:         shuffle($elements);
 336: 
 337:         return $this->newCollection($elements);
 338:     }
 339: 
 340:     /**
 341:      * {@inheritDoc}
 342:      */
 343:     public function sample($size = 10)
 344:     {
 345:         return $this->newCollection(new LimitIterator($this->shuffle(), 0, $size));
 346:     }
 347: 
 348:     /**
 349:      * {@inheritDoc}
 350:      */
 351:     public function take($size = 1, $from = 0)
 352:     {
 353:         return $this->newCollection(new LimitIterator($this, $from, $size));
 354:     }
 355: 
 356:     /**
 357:      * {@inheritDoc}
 358:      */
 359:     public function skip($howMany)
 360:     {
 361:         return $this->newCollection(new LimitIterator($this, $howMany));
 362:     }
 363: 
 364:     /**
 365:      * {@inheritDoc}
 366:      */
 367:     public function match(array $conditions)
 368:     {
 369:         return $this->filter($this->_createMatcherFilter($conditions));
 370:     }
 371: 
 372:     /**
 373:      * {@inheritDoc}
 374:      */
 375:     public function firstMatch(array $conditions)
 376:     {
 377:         return $this->match($conditions)->first();
 378:     }
 379: 
 380:     /**
 381:      * {@inheritDoc}
 382:      */
 383:     public function first()
 384:     {
 385:         $iterator = new LimitIterator($this, 0, 1);
 386:         foreach ($iterator as $result) {
 387:             return $result;
 388:         }
 389:     }
 390: 
 391:     /**
 392:      * {@inheritDoc}
 393:      */
 394:     public function last()
 395:     {
 396:         $iterator = $this->optimizeUnwrap();
 397:         if (is_array($iterator)) {
 398:             return array_pop($iterator);
 399:         }
 400: 
 401:         if ($iterator instanceof Countable) {
 402:             $count = count($iterator);
 403:             if ($count === 0) {
 404:                 return null;
 405:             }
 406:             $iterator = new LimitIterator($iterator, $count - 1, 1);
 407:         }
 408: 
 409:         $result = null;
 410:         foreach ($iterator as $result) {
 411:             // No-op
 412:         }
 413: 
 414:         return $result;
 415:     }
 416: 
 417:     /**
 418:      * {@inheritDoc}
 419:      */
 420:     public function takeLast($howMany)
 421:     {
 422:         if ($howMany < 1) {
 423:             throw new \InvalidArgumentException("The takeLast method requires a number greater than 0.");
 424:         }
 425: 
 426:         $iterator = $this->optimizeUnwrap();
 427:         if (is_array($iterator)) {
 428:             return $this->newCollection(array_slice($iterator, $howMany * -1));
 429:         }
 430: 
 431:         if ($iterator instanceof Countable) {
 432:             $count = count($iterator);
 433: 
 434:             if ($count === 0) {
 435:                 return $this->newCollection([]);
 436:             }
 437: 
 438:             $iterator = new LimitIterator($iterator, max(0, $count - $howMany), $howMany);
 439: 
 440:             return $this->newCollection($iterator);
 441:         }
 442: 
 443:         $generator = function ($iterator, $howMany) {
 444:             $result = [];
 445:             $bucket = 0;
 446:             $offset = 0;
 447: 
 448:             /**
 449:              * Consider the collection of elements [1, 2, 3, 4, 5, 6, 7, 8, 9], in order
 450:              * to get the last 4 elements, we can keep a buffer of 4 elements and
 451:              * fill it circularly using modulo logic, we use the $bucket variable
 452:              * to track the position to fill next in the buffer. This how the buffer
 453:              * looks like after 4 iterations:
 454:              *
 455:              * 0) 1 2 3 4 -- $bucket now goes back to 0, we have filled 4 elementes
 456:              * 1) 5 2 3 4 -- 5th iteration
 457:              * 2) 5 6 3 4 -- 6th iteration
 458:              * 3) 5 6 7 4 -- 7th iteration
 459:              * 4) 5 6 7 8 -- 8th iteration
 460:              * 5) 9 6 7 8
 461:              *
 462:              *  We can see that at the end of the iterations, the buffer contains all
 463:              *  the last four elements, just in the wrong order. How do we keep the
 464:              *  original order? Well, it turns out that the number of iteration also
 465:              *  give us a clue on what's going on, Let's add a marker for it now:
 466:              *
 467:              * 0) 1 2 3 4
 468:              *    ^ -- The 0) above now becomes the $offset variable
 469:              * 1) 5 2 3 4
 470:              *      ^ -- $offset = 1
 471:              * 2) 5 6 3 4
 472:              *        ^ -- $offset = 2
 473:              * 3) 5 6 7 4
 474:              *          ^ -- $offset = 3
 475:              * 4) 5 6 7 8
 476:              *    ^  -- We use module logic for $offset too
 477:              *          and as you can see each time $offset is 0, then the buffer
 478:              *          is sorted exactly as we need.
 479:              * 5) 9 6 7 8
 480:              *      ^ -- $offset = 1
 481:              *
 482:              * The $offset variable is a marker for splitting the buffer in two,
 483:              * elements to the right for the marker are the head of the final result,
 484:              * whereas the elements at the left are the tail. For example consider step 5)
 485:              * which has an offset of 1:
 486:              *
 487:              * - $head = elements to the right = [6, 7, 8]
 488:              * - $tail = elements to the left =  [9]
 489:              * - $result = $head + $tail = [6, 7, 8, 9]
 490:              *
 491:              * The logic above applies to collections of any size.
 492:              */
 493: 
 494:             foreach ($iterator as $k => $item) {
 495:                 $result[$bucket] = [$k, $item];
 496:                 $bucket = (++$bucket) % $howMany;
 497:                 $offset++;
 498:             }
 499: 
 500:             $offset = $offset % $howMany;
 501:             $head = array_slice($result, $offset);
 502:             $tail = array_slice($result, 0, $offset);
 503: 
 504:             foreach ($head as $v) {
 505:                 yield $v[0] => $v[1];
 506:             }
 507: 
 508:             foreach ($tail as $v) {
 509:                 yield $v[0] => $v[1];
 510:             }
 511:         };
 512: 
 513:         return $this->newCollection($generator($iterator, $howMany));
 514:     }
 515: 
 516:     /**
 517:      * {@inheritDoc}
 518:      */
 519:     public function append($items)
 520:     {
 521:         $list = new AppendIterator();
 522:         $list->append($this->unwrap());
 523:         $list->append($this->newCollection($items)->unwrap());
 524: 
 525:         return $this->newCollection($list);
 526:     }
 527: 
 528:     /**
 529:      * {@inheritDoc}
 530:      */
 531:     public function appendItem($item, $key = null)
 532:     {
 533:         if ($key !== null) {
 534:             $data = [$key => $item];
 535:         } else {
 536:             $data = [$item];
 537:         }
 538: 
 539:         return $this->append($data);
 540:     }
 541: 
 542:     /**
 543:      * {@inheritDoc}
 544:      */
 545:     public function prepend($items)
 546:     {
 547:         return $this->newCollection($items)->append($this);
 548:     }
 549: 
 550:     /**
 551:      * {@inheritDoc}
 552:      */
 553:     public function prependItem($item, $key = null)
 554:     {
 555:         if ($key !== null) {
 556:             $data = [$key => $item];
 557:         } else {
 558:             $data = [$item];
 559:         }
 560: 
 561:         return $this->prepend($data);
 562:     }
 563: 
 564:     /**
 565:      * {@inheritDoc}
 566:      */
 567:     public function combine($keyPath, $valuePath, $groupPath = null)
 568:     {
 569:         $options = [
 570:             'keyPath' => $this->_propertyExtractor($keyPath),
 571:             'valuePath' => $this->_propertyExtractor($valuePath),
 572:             'groupPath' => $groupPath ? $this->_propertyExtractor($groupPath) : null
 573:         ];
 574: 
 575:         $mapper = function ($value, $key, $mapReduce) use ($options) {
 576:             /** @var \Cake\Collection\Iterator\MapReduce $mapReduce */
 577:             $rowKey = $options['keyPath'];
 578:             $rowVal = $options['valuePath'];
 579: 
 580:             if (!$options['groupPath']) {
 581:                 $mapReduce->emit($rowVal($value, $key), $rowKey($value, $key));
 582: 
 583:                 return null;
 584:             }
 585: 
 586:             $key = $options['groupPath']($value, $key);
 587:             $mapReduce->emitIntermediate(
 588:                 [$rowKey($value, $key) => $rowVal($value, $key)],
 589:                 $key
 590:             );
 591:         };
 592: 
 593:         $reducer = function ($values, $key, $mapReduce) {
 594:             $result = [];
 595:             foreach ($values as $value) {
 596:                 $result += $value;
 597:             }
 598:             /** @var \Cake\Collection\Iterator\MapReduce $mapReduce */
 599:             $mapReduce->emit($result, $key);
 600:         };
 601: 
 602:         return $this->newCollection(new MapReduce($this->unwrap(), $mapper, $reducer));
 603:     }
 604: 
 605:     /**
 606:      * {@inheritDoc}
 607:      */
 608:     public function nest($idPath, $parentPath, $nestingKey = 'children')
 609:     {
 610:         $parents = [];
 611:         $idPath = $this->_propertyExtractor($idPath);
 612:         $parentPath = $this->_propertyExtractor($parentPath);
 613:         $isObject = true;
 614: 
 615:         $mapper = function ($row, $key, $mapReduce) use (&$parents, $idPath, $parentPath, $nestingKey) {
 616:             $row[$nestingKey] = [];
 617:             $id = $idPath($row, $key);
 618:             $parentId = $parentPath($row, $key);
 619:             $parents[$id] =& $row;
 620:             /** @var \Cake\Collection\Iterator\MapReduce $mapReduce */
 621:             $mapReduce->emitIntermediate($id, $parentId);
 622:         };
 623: 
 624:         $reducer = function ($values, $key, $mapReduce) use (&$parents, &$isObject, $nestingKey) {
 625:             static $foundOutType = false;
 626:             if (!$foundOutType) {
 627:                 $isObject = is_object(current($parents));
 628:                 $foundOutType = true;
 629:             }
 630:             if (empty($key) || !isset($parents[$key])) {
 631:                 foreach ($values as $id) {
 632:                     $parents[$id] = $isObject ? $parents[$id] : new ArrayIterator($parents[$id], 1);
 633:                     /** @var \Cake\Collection\Iterator\MapReduce $mapReduce */
 634:                     $mapReduce->emit($parents[$id]);
 635:                 }
 636: 
 637:                 return null;
 638:             }
 639: 
 640:             $children = [];
 641:             foreach ($values as $id) {
 642:                 $children[] =& $parents[$id];
 643:             }
 644:             $parents[$key][$nestingKey] = $children;
 645:         };
 646: 
 647:         return $this->newCollection(new MapReduce($this->unwrap(), $mapper, $reducer))
 648:             ->map(function ($value) use (&$isObject) {
 649:                 /** @var \ArrayIterator $value */
 650:                 return $isObject ? $value : $value->getArrayCopy();
 651:             });
 652:     }
 653: 
 654:     /**
 655:      * {@inheritDoc}
 656:      *
 657:      * @return \Cake\Collection\Iterator\InsertIterator
 658:      */
 659:     public function insert($path, $values)
 660:     {
 661:         return new InsertIterator($this->unwrap(), $path, $values);
 662:     }
 663: 
 664:     /**
 665:      * {@inheritDoc}
 666:      */
 667:     public function toArray($preserveKeys = true)
 668:     {
 669:         $iterator = $this->unwrap();
 670:         if ($iterator instanceof ArrayIterator) {
 671:             $items = $iterator->getArrayCopy();
 672: 
 673:             return $preserveKeys ? $items : array_values($items);
 674:         }
 675:         // RecursiveIteratorIterator can return duplicate key values causing
 676:         // data loss when converted into an array
 677:         if ($preserveKeys && get_class($iterator) === 'RecursiveIteratorIterator') {
 678:             $preserveKeys = false;
 679:         }
 680: 
 681:         return iterator_to_array($this, $preserveKeys);
 682:     }
 683: 
 684:     /**
 685:      * {@inheritDoc}
 686:      */
 687:     public function toList()
 688:     {
 689:         return $this->toArray(false);
 690:     }
 691: 
 692:     /**
 693:      * {@inheritDoc}
 694:      */
 695:     public function jsonSerialize()
 696:     {
 697:         return $this->toArray();
 698:     }
 699: 
 700:     /**
 701:      * {@inheritDoc}
 702:      */
 703:     public function compile($preserveKeys = true)
 704:     {
 705:         return $this->newCollection($this->toArray($preserveKeys));
 706:     }
 707: 
 708:     /**
 709:      * {@inheritDoc}
 710:      */
 711:     public function lazy()
 712:     {
 713:         $generator = function () {
 714:             foreach ($this->unwrap() as $k => $v) {
 715:                 yield $k => $v;
 716:             }
 717:         };
 718: 
 719:         return $this->newCollection($generator());
 720:     }
 721: 
 722:     /**
 723:      * {@inheritDoc}
 724:      *
 725:      * @return \Cake\Collection\Iterator\BufferedIterator
 726:      */
 727:     public function buffered()
 728:     {
 729:         return new BufferedIterator($this->unwrap());
 730:     }
 731: 
 732:     /**
 733:      * {@inheritDoc}
 734:      *
 735:      * @return \Cake\Collection\Iterator\TreeIterator
 736:      */
 737:     public function listNested($dir = 'desc', $nestingKey = 'children')
 738:     {
 739:         $dir = strtolower($dir);
 740:         $modes = [
 741:             'desc' => TreeIterator::SELF_FIRST,
 742:             'asc' => TreeIterator::CHILD_FIRST,
 743:             'leaves' => TreeIterator::LEAVES_ONLY
 744:         ];
 745: 
 746:         return new TreeIterator(
 747:             new NestIterator($this, $nestingKey),
 748:             isset($modes[$dir]) ? $modes[$dir] : $dir
 749:         );
 750:     }
 751: 
 752:     /**
 753:      * {@inheritDoc}
 754:      *
 755:      * @return \Cake\Collection\Iterator\StoppableIterator
 756:      */
 757:     public function stopWhen($condition)
 758:     {
 759:         if (!is_callable($condition)) {
 760:             $condition = $this->_createMatcherFilter($condition);
 761:         }
 762: 
 763:         return new StoppableIterator($this->unwrap(), $condition);
 764:     }
 765: 
 766:     /**
 767:      * {@inheritDoc}
 768:      */
 769:     public function unfold(callable $transformer = null)
 770:     {
 771:         if ($transformer === null) {
 772:             $transformer = function ($item) {
 773:                 return $item;
 774:             };
 775:         }
 776: 
 777:         return $this->newCollection(
 778:             new RecursiveIteratorIterator(
 779:                 new UnfoldIterator($this->unwrap(), $transformer),
 780:                 RecursiveIteratorIterator::LEAVES_ONLY
 781:             )
 782:         );
 783:     }
 784: 
 785:     /**
 786:      * {@inheritDoc}
 787:      */
 788:     public function through(callable $handler)
 789:     {
 790:         $result = $handler($this);
 791: 
 792:         return $result instanceof CollectionInterface ? $result : $this->newCollection($result);
 793:     }
 794: 
 795:     /**
 796:      * {@inheritDoc}
 797:      */
 798:     public function zip($items)
 799:     {
 800:         return new ZipIterator(array_merge([$this->unwrap()], func_get_args()));
 801:     }
 802: 
 803:     /**
 804:      * {@inheritDoc}
 805:      */
 806:     public function zipWith($items, $callable)
 807:     {
 808:         if (func_num_args() > 2) {
 809:             $items = func_get_args();
 810:             $callable = array_pop($items);
 811:         } else {
 812:             $items = [$items];
 813:         }
 814: 
 815:         return new ZipIterator(array_merge([$this->unwrap()], $items), $callable);
 816:     }
 817: 
 818:     /**
 819:      * {@inheritDoc}
 820:      */
 821:     public function chunk($chunkSize)
 822:     {
 823:         return $this->map(function ($v, $k, $iterator) use ($chunkSize) {
 824:             $values = [$v];
 825:             for ($i = 1; $i < $chunkSize; $i++) {
 826:                 $iterator->next();
 827:                 if (!$iterator->valid()) {
 828:                     break;
 829:                 }
 830:                 $values[] = $iterator->current();
 831:             }
 832: 
 833:             return $values;
 834:         });
 835:     }
 836: 
 837:     /**
 838:      * {@inheritDoc}
 839:      */
 840:     public function chunkWithKeys($chunkSize, $preserveKeys = true)
 841:     {
 842:         return $this->map(function ($v, $k, $iterator) use ($chunkSize, $preserveKeys) {
 843:             $key = 0;
 844:             if ($preserveKeys) {
 845:                 $key = $k;
 846:             }
 847:             $values = [$key => $v];
 848:             for ($i = 1; $i < $chunkSize; $i++) {
 849:                 $iterator->next();
 850:                 if (!$iterator->valid()) {
 851:                     break;
 852:                 }
 853:                 if ($preserveKeys) {
 854:                     $values[$iterator->key()] = $iterator->current();
 855:                 } else {
 856:                     $values[] = $iterator->current();
 857:                 }
 858:             }
 859: 
 860:             return $values;
 861:         });
 862:     }
 863: 
 864:     /**
 865:      * {@inheritDoc}
 866:      */
 867:     public function isEmpty()
 868:     {
 869:         foreach ($this as $el) {
 870:             return false;
 871:         }
 872: 
 873:         return true;
 874:     }
 875: 
 876:     /**
 877:      * {@inheritDoc}
 878:      */
 879:     public function unwrap()
 880:     {
 881:         $iterator = $this;
 882:         while (get_class($iterator) === 'Cake\Collection\Collection') {
 883:             $iterator = $iterator->getInnerIterator();
 884:         }
 885: 
 886:         if ($iterator !== $this && $iterator instanceof CollectionInterface) {
 887:             $iterator = $iterator->unwrap();
 888:         }
 889: 
 890:         return $iterator;
 891:     }
 892: 
 893:     /**
 894:      * Backwards compatible wrapper for unwrap()
 895:      *
 896:      * @return \Traversable
 897:      * @deprecated 3.0.10 Will be removed in 4.0.0
 898:      */
 899:     // @codingStandardsIgnoreLine
 900:     public function _unwrap()
 901:     {
 902:         deprecationWarning('CollectionTrait::_unwrap() is deprecated. Use CollectionTrait::unwrap() instead.');
 903: 
 904:         return $this->unwrap();
 905:     }
 906: 
 907:     /**
 908:      * @param callable|null $operation Operation
 909:      * @param callable|null $filter Filter
 910:      * @return \Cake\Collection\CollectionInterface
 911:      * @throws \LogicException
 912:      */
 913:     public function cartesianProduct(callable $operation = null, callable $filter = null)
 914:     {
 915:         if ($this->isEmpty()) {
 916:             return $this->newCollection([]);
 917:         }
 918: 
 919:         $collectionArrays = [];
 920:         $collectionArraysKeys = [];
 921:         $collectionArraysCounts = [];
 922: 
 923:         foreach ($this->toList() as $value) {
 924:             $valueCount = count($value);
 925:             if ($valueCount !== count($value, COUNT_RECURSIVE)) {
 926:                 throw new LogicException('Cannot find the cartesian product of a multidimensional array');
 927:             }
 928: 
 929:             $collectionArraysKeys[] = array_keys($value);
 930:             $collectionArraysCounts[] = $valueCount;
 931:             $collectionArrays[] = $value;
 932:         }
 933: 
 934:         $result = [];
 935:         $lastIndex = count($collectionArrays) - 1;
 936:         // holds the indexes of the arrays that generate the current combination
 937:         $currentIndexes = array_fill(0, $lastIndex + 1, 0);
 938: 
 939:         $changeIndex = $lastIndex;
 940: 
 941:         while (!($changeIndex === 0 && $currentIndexes[0] === $collectionArraysCounts[0])) {
 942:             $currentCombination = array_map(function ($value, $keys, $index) {
 943:                 return $value[$keys[$index]];
 944:             }, $collectionArrays, $collectionArraysKeys, $currentIndexes);
 945: 
 946:             if ($filter === null || $filter($currentCombination)) {
 947:                 $result[] = ($operation === null) ? $currentCombination : $operation($currentCombination);
 948:             }
 949: 
 950:             $currentIndexes[$lastIndex]++;
 951: 
 952:             for ($changeIndex = $lastIndex; $currentIndexes[$changeIndex] === $collectionArraysCounts[$changeIndex] && $changeIndex > 0; $changeIndex--) {
 953:                 $currentIndexes[$changeIndex] = 0;
 954:                 $currentIndexes[$changeIndex - 1]++;
 955:             }
 956:         }
 957: 
 958:         return $this->newCollection($result);
 959:     }
 960: 
 961:     /**
 962:      * {@inheritDoc}
 963:      *
 964:      * @return \Cake\Collection\CollectionInterface
 965:      * @throws \LogicException
 966:      */
 967:     public function transpose()
 968:     {
 969:         $arrayValue = $this->toList();
 970:         $length = count(current($arrayValue));
 971:         $result = [];
 972:         foreach ($arrayValue as $column => $row) {
 973:             if (count($row) != $length) {
 974:                 throw new LogicException('Child arrays do not have even length');
 975:             }
 976:         }
 977: 
 978:         for ($column = 0; $column < $length; $column++) {
 979:             $result[] = array_column($arrayValue, $column);
 980:         }
 981: 
 982:         return $this->newCollection($result);
 983:     }
 984: 
 985:     /**
 986:      * {@inheritDoc}
 987:      *
 988:      * @return int
 989:      */
 990:     public function count()
 991:     {
 992:         $traversable = $this->optimizeUnwrap();
 993: 
 994:         if (is_array($traversable)) {
 995:             return count($traversable);
 996:         }
 997: 
 998:         return iterator_count($traversable);
 999:     }
1000: 
1001:     /**
1002:      * {@inheritDoc}
1003:      *
1004:      * @return int
1005:      */
1006:     public function countKeys()
1007:     {
1008:         return count($this->toArray());
1009:     }
1010: 
1011:     /**
1012:      * Unwraps this iterator and returns the simplest
1013:      * traversable that can be used for getting the data out
1014:      *
1015:      * @return \Traversable|array
1016:      */
1017:     protected function optimizeUnwrap()
1018:     {
1019:         $iterator = $this->unwrap();
1020: 
1021:         if (get_class($iterator) === ArrayIterator::class) {
1022:             $iterator = $iterator->getArrayCopy();
1023:         }
1024: 
1025:         return $iterator;
1026:     }
1027: }
1028: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs