vendor/contao/core-bundle/src/Resources/contao/library/Contao/Model/Collection.php line 124

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao\Model;
  10. use Contao\Database\Result;
  11. use Contao\Model;
  12. /**
  13.  * The class handles traversing a set of models and lazy loads the database
  14.  * result rows upon their first usage.
  15.  *
  16.  * @author Leo Feyer <https://github.com/leofeyer>
  17.  */
  18. class Collection implements \ArrayAccess, \Countable, \IteratorAggregate
  19. {
  20.     /**
  21.      * Table name
  22.      * @var string
  23.      */
  24.     protected $strTable;
  25.     /**
  26.      * Current index
  27.      * @var integer
  28.      */
  29.     protected $intIndex = -1;
  30.     /**
  31.      * Models
  32.      * @var Model[]
  33.      */
  34.     protected $arrModels = array();
  35.     /**
  36.      * Create a new collection
  37.      *
  38.      * @param array  $arrModels An array of models
  39.      * @param string $strTable  The table name
  40.      *
  41.      * @throws \InvalidArgumentException
  42.      */
  43.     public function __construct(array $arrModels$strTable)
  44.     {
  45.         $arrModels array_values($arrModels);
  46.         foreach ($arrModels as $objModel)
  47.         {
  48.             if (!$objModel instanceof Model)
  49.             {
  50.                 throw new \InvalidArgumentException('Invalid type: ' . \gettype($objModel));
  51.             }
  52.         }
  53.         $this->arrModels $arrModels;
  54.         $this->strTable  $strTable;
  55.     }
  56.     /**
  57.      * Set an object property
  58.      *
  59.      * @param string $strKey   The property name
  60.      * @param mixed  $varValue The property value
  61.      */
  62.     public function __set($strKey$varValue)
  63.     {
  64.         if ($this->intIndex 0)
  65.         {
  66.             $this->first();
  67.         }
  68.         $this->arrModels[$this->intIndex]->$strKey $varValue;
  69.     }
  70.     /**
  71.      * Return an object property
  72.      *
  73.      * @param string $strKey The property name
  74.      *
  75.      * @return mixed|null The property value or null
  76.      */
  77.     public function __get($strKey)
  78.     {
  79.         if ($this->intIndex 0)
  80.         {
  81.             $this->first();
  82.         }
  83.         return $this->arrModels[$this->intIndex]->$strKey ?? null;
  84.     }
  85.     /**
  86.      * Check whether a property is set
  87.      *
  88.      * @param string $strKey The property name
  89.      *
  90.      * @return boolean True if the property is set
  91.      */
  92.     public function __isset($strKey)
  93.     {
  94.         if ($this->intIndex 0)
  95.         {
  96.             $this->first();
  97.         }
  98.         return isset($this->arrModels[$this->intIndex]->$strKey);
  99.     }
  100.     /**
  101.      * Create a new collection from a database result
  102.      *
  103.      * @param Result $objResult The database result object
  104.      * @param string $strTable  The table name
  105.      *
  106.      * @return static The model collection
  107.      */
  108.     public static function createFromDbResult(Result $objResult$strTable)
  109.     {
  110.         $arrModels = array();
  111.         $strClass Model::getClassFromTable($strTable);
  112.         while ($objResult->next())
  113.         {
  114.             /** @var Model $strClass */
  115.             $objModel Registry::getInstance()->fetch($strTable$objResult->{$strClass::getPk()});
  116.             if ($objModel !== null)
  117.             {
  118.                 $objModel->mergeRow($objResult->row());
  119.                 $arrModels[] = $objModel;
  120.             }
  121.             else
  122.             {
  123.                 $arrModels[] = new $strClass($objResult);
  124.             }
  125.         }
  126.         return new static($arrModels$strTable);
  127.     }
  128.     /**
  129.      * Return the current row as associative array
  130.      *
  131.      * @return array The current row as array
  132.      */
  133.     public function row()
  134.     {
  135.         if ($this->intIndex 0)
  136.         {
  137.             $this->first();
  138.         }
  139.         return $this->arrModels[$this->intIndex]->row();
  140.     }
  141.     /**
  142.      * Set the current row from an array
  143.      *
  144.      * @param array $arrData The row data as array
  145.      *
  146.      * @return static The model collection object
  147.      */
  148.     public function setRow(array $arrData)
  149.     {
  150.         if ($this->intIndex 0)
  151.         {
  152.             $this->first();
  153.         }
  154.         $this->arrModels[$this->intIndex]->setRow($arrData);
  155.         return $this;
  156.     }
  157.     /**
  158.      * Save the current model
  159.      *
  160.      * @return static The model collection object
  161.      */
  162.     public function save()
  163.     {
  164.         if ($this->intIndex 0)
  165.         {
  166.             $this->first();
  167.         }
  168.         $this->arrModels[$this->intIndex]->save();
  169.         return $this;
  170.     }
  171.     /**
  172.      * Delete the current model and return the number of affected rows
  173.      *
  174.      * @return integer The number of affected rows
  175.      */
  176.     public function delete()
  177.     {
  178.         if ($this->intIndex 0)
  179.         {
  180.             $this->first();
  181.         }
  182.         return $this->arrModels[$this->intIndex]->delete();
  183.     }
  184.     /**
  185.      * Return the models as array
  186.      *
  187.      * @return Model[] An array of models
  188.      */
  189.     public function getModels()
  190.     {
  191.         return $this->arrModels;
  192.     }
  193.     /**
  194.      * Lazy load related records
  195.      *
  196.      * @param string $strKey The property name
  197.      *
  198.      * @return Collection|Model The model or a model collection if there are multiple rows
  199.      */
  200.     public function getRelated($strKey)
  201.     {
  202.         if ($this->intIndex 0)
  203.         {
  204.             $this->first();
  205.         }
  206.         return $this->arrModels[$this->intIndex]->getRelated($strKey);
  207.     }
  208.     /**
  209.      * Return the number of rows in the result set
  210.      *
  211.      * @return integer The number of rows
  212.      */
  213.     #[\ReturnTypeWillChange]
  214.     public function count()
  215.     {
  216.         return \count($this->arrModels);
  217.     }
  218.     /**
  219.      * Go to the first row
  220.      *
  221.      * @return static The model collection object
  222.      */
  223.     public function first()
  224.     {
  225.         $this->intIndex 0;
  226.         return $this;
  227.     }
  228.     /**
  229.      * Go to the previous row
  230.      *
  231.      * @return Collection|false The model collection object or false if there is no previous row
  232.      */
  233.     public function prev()
  234.     {
  235.         if ($this->intIndex 1)
  236.         {
  237.             return false;
  238.         }
  239.         --$this->intIndex;
  240.         return $this;
  241.     }
  242.     /**
  243.      * Return the current model
  244.      *
  245.      * @return Model The model object
  246.      */
  247.     public function current()
  248.     {
  249.         if ($this->intIndex 0)
  250.         {
  251.             $this->first();
  252.         }
  253.         return $this->arrModels[$this->intIndex];
  254.     }
  255.     /**
  256.      * Go to the next row
  257.      *
  258.      * @return Collection|false The model collection object or false if there is no next row
  259.      */
  260.     public function next()
  261.     {
  262.         if (!isset($this->arrModels[$this->intIndex 1]))
  263.         {
  264.             return false;
  265.         }
  266.         ++$this->intIndex;
  267.         return $this;
  268.     }
  269.     /**
  270.      * Go to the last row
  271.      *
  272.      * @return static The model collection object
  273.      */
  274.     public function last()
  275.     {
  276.         $this->intIndex = \count($this->arrModels) - 1;
  277.         return $this;
  278.     }
  279.     /**
  280.      * Reset the model
  281.      *
  282.      * @return static The model collection object
  283.      */
  284.     public function reset()
  285.     {
  286.         $this->intIndex = -1;
  287.         return $this;
  288.     }
  289.     /**
  290.      * Fetch a column of each row
  291.      *
  292.      * @param string $strKey The property name
  293.      *
  294.      * @return array An array with all property values
  295.      */
  296.     public function fetchEach($strKey)
  297.     {
  298.         $this->reset();
  299.         $return = array();
  300.         while ($this->next())
  301.         {
  302.             $strPk $this->current()->getPk();
  303.             if ($strKey != 'id' && isset($this->$strPk))
  304.             {
  305.                 $return[$this->$strPk] = $this->$strKey;
  306.             }
  307.             else
  308.             {
  309.                 $return[] = $this->$strKey;
  310.             }
  311.         }
  312.         return $return;
  313.     }
  314.     /**
  315.      * Fetch all columns of every row
  316.      *
  317.      * @return array An array with all rows and columns
  318.      */
  319.     public function fetchAll()
  320.     {
  321.         $this->reset();
  322.         $return = array();
  323.         while ($this->next())
  324.         {
  325.             $return[] = $this->row();
  326.         }
  327.         return $return;
  328.     }
  329.     /**
  330.      * Check whether an offset exists
  331.      *
  332.      * @param integer $offset The offset
  333.      *
  334.      * @return boolean True if the offset exists
  335.      */
  336.     #[\ReturnTypeWillChange]
  337.     public function offsetExists($offset)
  338.     {
  339.         return isset($this->arrModels[$offset]);
  340.     }
  341.     /**
  342.      * Retrieve a particular offset
  343.      *
  344.      * @param integer $offset The offset
  345.      *
  346.      * @return Model|null The model or null
  347.      */
  348.     #[\ReturnTypeWillChange]
  349.     public function offsetGet($offset)
  350.     {
  351.         return $this->arrModels[$offset];
  352.     }
  353.     /**
  354.      * Set a particular offset
  355.      *
  356.      * @param integer $offset The offset
  357.      * @param mixed   $value  The value to set
  358.      *
  359.      * @throws \RuntimeException The collection is immutable
  360.      */
  361.     #[\ReturnTypeWillChange]
  362.     public function offsetSet($offset$value)
  363.     {
  364.         throw new \RuntimeException('This collection is immutable');
  365.     }
  366.     /**
  367.      * Unset a particular offset
  368.      *
  369.      * @param integer $offset The offset
  370.      *
  371.      * @throws \RuntimeException The collection is immutable
  372.      */
  373.     #[\ReturnTypeWillChange]
  374.     public function offsetUnset($offset)
  375.     {
  376.         throw new \RuntimeException('This collection is immutable');
  377.     }
  378.     /**
  379.      * Retrieve the iterator object
  380.      *
  381.      * @return \ArrayIterator The iterator object
  382.      */
  383.     #[\ReturnTypeWillChange]
  384.     public function getIterator()
  385.     {
  386.         return new \ArrayIterator($this->arrModels);
  387.     }
  388. }
  389. class_alias(Collection::class, 'Model\Collection');