vendor/jackalope/jackalope/src/Jackalope/NodePathIterator.php line 48

  1. <?php
  2. namespace Jackalope;
  3. use ArrayAccess;
  4. use Countable;
  5. use InvalidArgumentException;
  6. use SeekableIterator;
  7. /**
  8.  * @license http://www.apache.org/licenses Apache License Version 2.0, January 2004
  9.  * @license http://opensource.org/licenses/MIT MIT License
  10.  */
  11. class NodePathIterator implements SeekableIteratorArrayAccessCountable
  12. {
  13.     /**
  14.      * @var int
  15.      */
  16.     protected $position 0;
  17.     /**
  18.      * @var array
  19.      */
  20.     protected $nodes = [];
  21.     /**
  22.      * @var array
  23.      */
  24.     protected $paths;
  25.     protected $typeFilter;
  26.     protected $class;
  27.     /**
  28.      * @var int
  29.      */
  30.     protected $count 0;
  31.     protected $batchSize;
  32.     public function __construct(
  33.         ObjectManager $objectManager,
  34.         $paths,
  35.         $class Node::class,
  36.         $typeFilter = [],
  37.         $batchSize 50
  38.     ) {
  39.         $this->objectManager $objectManager;
  40.         $this->paths array_values((array) $paths); // ensure paths are indexed numerically
  41.         $this->batchSize $batchSize;
  42.         $this->typeFilter $typeFilter;
  43.         $this->class $class;
  44.         $this->loadBatch();
  45.     }
  46.     /**
  47.      * Return the batchSize
  48.      *
  49.      * @return integer
  50.      */
  51.     public function getBatchSize()
  52.     {
  53.         return $this->batchSize;
  54.     }
  55.     /**
  56.      * Return the type filter
  57.      *
  58.      * @return string
  59.      */
  60.     public function getTypeFilter()
  61.     {
  62.         return $this->typeFilter;
  63.     }
  64.     /**
  65.      * {@inheritDoc}
  66.      */
  67.     #[\ReturnTypeWillChange]
  68.     public function current()
  69.     {
  70.         return $this->nodes[$this->paths[$this->position]];
  71.     }
  72.     /**
  73.      * {@inheritDoc}
  74.      */
  75.     #[\ReturnTypeWillChange]
  76.     public function next()
  77.     {
  78.         $this->position++;
  79.     }
  80.     /**
  81.      * {@inheritDoc}
  82.      */
  83.     #[\ReturnTypeWillChange]
  84.     public function rewind()
  85.     {
  86.         $this->position 0;
  87.     }
  88.     /**
  89.      * {@inheritDoc}
  90.      */
  91.     #[\ReturnTypeWillChange]
  92.     public function valid()
  93.     {
  94.         if (!isset($this->paths[$this->position])) {
  95.             return false;
  96.         }
  97.         $path $this->paths[$this->position];
  98.         // skip any paths which have been filtered in userland
  99.         // and move on
  100.         if ($path === null) {
  101.             $this->position++;
  102.             return $this->valid();
  103.         }
  104.         if (!array_key_exists($path$this->nodes)) {
  105.             $this->loadBatch();
  106.         }
  107.         if (empty($this->nodes[$path])) {
  108.             $this->position++;
  109.             return $this->valid();
  110.         }
  111.         return true;
  112.     }
  113.     /**
  114.      * {@inheritDoc}
  115.      */
  116.     #[\ReturnTypeWillChange]
  117.     public function key()
  118.     {
  119.         return $this->paths[$this->position];
  120.     }
  121.     /**
  122.      * Load a batch of records according to the
  123.      * batch size.
  124.      *
  125.      * @param integer $position - Optional position to start from
  126.      */
  127.     protected function loadBatch($position null)
  128.     {
  129.         if (=== count($this->paths)) {
  130.             return;
  131.         }
  132.         $paths array_slice(
  133.             $this->paths,
  134.             $position $position $this->position,
  135.             $this->batchSize
  136.         );
  137.         $nodes $this->objectManager->getNodesByPathAsArray(
  138.             $paths,
  139.             $this->class,
  140.             $this->typeFilter
  141.         );
  142.         foreach ($paths as $path) {
  143.             if (isset($nodes[$path]) && $nodes[$path] !== '') {
  144.                 $this->nodes[$path] =  $nodes[$path];
  145.                 $this->count++;
  146.             } else {
  147.                 $this->nodes[$path] =  null;
  148.             }
  149.         }
  150.     }
  151.     /**
  152.      * Ensure that the given path is loaded from the database.
  153.      * We will iterate over the batches until we either get to
  154.      * the end or we find the node we are looking for.
  155.      *
  156.      * Subsequent calls will start loading from the first path
  157.      * which does not have a corresponding array key in the nodes array
  158.      * - if the node is indeed not already loaded.
  159.      *
  160.      * @param integer $offset
  161.      */
  162.     protected function ensurePathLoaded($offset)
  163.     {
  164.         if (count($this->paths) > 0) {
  165.             if (!array_key_exists($offset$this->nodes)) {
  166.                 // start loading batches from the position of the first
  167.                 // "missing" node
  168.                 $position null;
  169.                 foreach ($this->paths as $position => $path) {
  170.                     if (!array_key_exists($path$this->nodes)) {
  171.                         break;
  172.                     }
  173.                 }
  174.                 while (isset($this->paths[$position])) {
  175.                     // keep loading batches until we get to the end of the paths
  176.                     // or we find the one we want.
  177.                     $this->loadBatch($position);
  178.                     $position += $this->batchSize;
  179.                     if (array_key_exists($offset$this->nodes)) {
  180.                         break;
  181.                     }
  182.                 }
  183.             }
  184.         }
  185.         // if it wasn't found, it doesn't exist, set it to null
  186.         if (!array_key_exists($offset$this->nodes)) {
  187.             $this->nodes[$offset] = null;
  188.         }
  189.     }
  190.     /**
  191.      * {@inheritDoc}
  192.      */
  193.     #[\ReturnTypeWillChange]
  194.     public function offsetExists($offset)
  195.     {
  196.         $this->ensurePathLoaded($offset);
  197.         return $this->nodes[$offset] === null false true;
  198.     }
  199.     /**
  200.      * {@inheritDoc}
  201.      */
  202.     #[\ReturnTypeWillChange]
  203.     public function offsetGet($offset)
  204.     {
  205.         $this->ensurePathLoaded($offset);
  206.         return $this->nodes[$offset];
  207.     }
  208.     /**
  209.      * {@inheritDoc}
  210.      */
  211.     #[\ReturnTypeWillChange]
  212.     public function offsetSet($offset$value)
  213.     {
  214.         throw new InvalidArgumentException('Node path collection is read only');
  215.     }
  216.     /**
  217.      * {@inheritDoc}
  218.      */
  219.     #[\ReturnTypeWillChange]
  220.     public function offsetUnset($offset)
  221.     {
  222.         throw new InvalidArgumentException('Node path collection is read only');
  223.     }
  224.     /**
  225.      * {@inheritDoc}
  226.      */
  227.     #[\ReturnTypeWillChange]
  228.     public function seek($position)
  229.     {
  230.         $this->position $position;
  231.     }
  232.     /**
  233.      * {@inheritDoc}
  234.      */
  235.     #[\ReturnTypeWillChange]
  236.     public function count()
  237.     {
  238.         $this->ensurePathLoaded(count($this->paths));
  239.         return $this->count;
  240.     }
  241. }