Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 39 and 400] [Versions 400 and 401]

   1  <?php
   2  /*
   3   * Copyright 2017 MongoDB, Inc.
   4   *
   5   * Licensed under the Apache License, Version 2.0 (the "License");
   6   * you may not use this file except in compliance with the License.
   7   * You may obtain a copy of the License at
   8   *
   9   *   http://www.apache.org/licenses/LICENSE-2.0
  10   *
  11   * Unless required by applicable law or agreed to in writing, software
  12   * distributed under the License is distributed on an "AS IS" BASIS,
  13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14   * See the License for the specific language governing permissions and
  15   * limitations under the License.
  16   */
  17  
  18  namespace MongoDB\Model;
  19  
  20  use Countable;
  21  use Iterator;
  22  use IteratorIterator;
  23  use Traversable;
  24  use function count;
  25  use function current;
  26  use function key;
  27  use function next;
  28  use function reset;
  29  
  30  /**
  31   * Iterator for wrapping a Traversable and caching its results.
  32   *
  33   * By caching results, this iterators allows a Traversable to be counted and
  34   * rewound multiple times, even if the wrapped object does not natively support
  35   * those operations (e.g. MongoDB\Driver\Cursor).
  36   *
  37   * @internal
  38   */
  39  class CachingIterator implements Countable, Iterator
  40  {
  41      /** @var array */
  42      private $items = [];
  43  
  44      /** @var IteratorIterator */
  45      private $iterator;
  46  
  47      /** @var boolean */
  48      private $iteratorAdvanced = false;
  49  
  50      /** @var boolean */
  51      private $iteratorExhausted = false;
  52  
  53      /**
  54       * Initialize the iterator and stores the first item in the cache. This
  55       * effectively rewinds the Traversable and the wrapping IteratorIterator.
  56       *  Additionally, this mimics behavior of the SPL iterators and allows users
  57       * to omit an explicit call * to rewind() before using the other methods.
  58       *
  59       * @param Traversable $traversable
  60       */
  61      public function __construct(Traversable $traversable)
  62      {
  63          $this->iterator = new IteratorIterator($traversable);
  64  
  65          $this->iterator->rewind();
  66          $this->storeCurrentItem();
  67      }
  68  
  69      /**
  70       * @see http://php.net/countable.count
  71       * @return integer
  72       */
  73      public function count()
  74      {
  75          $this->exhaustIterator();
  76  
  77          return count($this->items);
  78      }
  79  
  80      /**
  81       * @see http://php.net/iterator.current
  82       * @return mixed
  83       */
  84      public function current()
  85      {
  86          return current($this->items);
  87      }
  88  
  89      /**
  90       * @see http://php.net/iterator.key
  91       * @return mixed
  92       */
  93      public function key()
  94      {
  95          return key($this->items);
  96      }
  97  
  98      /**
  99       * @see http://php.net/iterator.next
 100       * @return void
 101       */
 102      public function next()
 103      {
 104          if (! $this->iteratorExhausted) {
 105              $this->iteratorAdvanced = true;
 106              $this->iterator->next();
 107  
 108              $this->storeCurrentItem();
 109  
 110              $this->iteratorExhausted = ! $this->iterator->valid();
 111          }
 112  
 113          next($this->items);
 114      }
 115  
 116      /**
 117       * @see http://php.net/iterator.rewind
 118       * @return void
 119       */
 120      public function rewind()
 121      {
 122          /* If the iterator has advanced, exhaust it now so that future iteration
 123           * can rely on the cache.
 124           */
 125          if ($this->iteratorAdvanced) {
 126              $this->exhaustIterator();
 127          }
 128  
 129          reset($this->items);
 130      }
 131  
 132      /**
 133       * @see http://php.net/iterator.valid
 134       * @return boolean
 135       */
 136      public function valid()
 137      {
 138          return $this->key() !== null;
 139      }
 140  
 141      /**
 142       * Ensures that the inner iterator is fully consumed and cached.
 143       */
 144      private function exhaustIterator()
 145      {
 146          while (! $this->iteratorExhausted) {
 147              $this->next();
 148          }
 149      }
 150  
 151      /**
 152       * Stores the current item in the cache.
 153       */
 154      private function storeCurrentItem()
 155      {
 156          $key = $this->iterator->key();
 157  
 158          if ($key === null) {
 159              return;
 160          }
 161  
 162          $this->items[$key] = $this->iterator->current();
 163      }
 164  }