vendor/propel/propel/src/Propel/Runtime/Collection/ObjectCollection.php line 24

Open in your IDE?
  1. <?php
  2. /**
  3.  * MIT License. This file is part of the Propel package.
  4.  * For the full copyright and license information, please view the LICENSE
  5.  * file that was distributed with this source code.
  6.  */
  7. namespace Propel\Runtime\Collection;
  8. use Propel\Runtime\ActiveQuery\PropelQuery;
  9. use Propel\Runtime\Collection\Exception\ReadOnlyModelException;
  10. use Propel\Runtime\Collection\Exception\UnsupportedRelationException;
  11. use Propel\Runtime\Exception\RuntimeException;
  12. use Propel\Runtime\Map\RelationMap;
  13. use Propel\Runtime\Map\TableMap;
  14. use Propel\Runtime\Propel;
  15. /**
  16.  * Class for iterating over a list of Propel objects
  17.  *
  18.  * @author Francois Zaninotto
  19.  */
  20. class ObjectCollection extends Collection
  21. {
  22.     /**
  23.      * @var array
  24.      */
  25.     protected $index = [];
  26.     /**
  27.      * @var array
  28.      */
  29.     protected $indexSplHash = [];
  30.     /**
  31.      * @param array $data
  32.      */
  33.     public function __construct($data = [])
  34.     {
  35.         parent::__construct($data);
  36.         $this->rebuildIndex();
  37.     }
  38.     /**
  39.      * @param array $input
  40.      *
  41.      * @return void
  42.      */
  43.     public function exchangeArray($input)
  44.     {
  45.         $this->data $input;
  46.         $this->rebuildIndex();
  47.     }
  48.     /**
  49.      * @param array $data
  50.      *
  51.      * @return void
  52.      */
  53.     public function setData($data)
  54.     {
  55.         parent::setData($data);
  56.         $this->rebuildIndex();
  57.     }
  58.     /**
  59.      * Save all the elements in the collection
  60.      *
  61.      * @param \Propel\Runtime\Connection\ConnectionInterface|null $con
  62.      *
  63.      * @throws \Propel\Runtime\Collection\Exception\ReadOnlyModelException
  64.      *
  65.      * @return void
  66.      */
  67.     public function save($con null)
  68.     {
  69.         if (!method_exists($this->getFullyQualifiedModel(), 'save')) {
  70.             throw new ReadOnlyModelException('Cannot save objects on a read-only model');
  71.         }
  72.         if ($con === null) {
  73.             $con $this->getWriteConnection();
  74.         }
  75.         $con->transaction(function () use ($con) {
  76.             /** @var \Propel\Runtime\ActiveRecord\ActiveRecordInterface $element */
  77.             foreach ($this as $element) {
  78.                 $element->save($con);
  79.             }
  80.         });
  81.     }
  82.     /**
  83.      * Delete all the elements in the collection
  84.      *
  85.      * @param \Propel\Runtime\Connection\ConnectionInterface|null $con
  86.      *
  87.      * @throws \Propel\Runtime\Collection\Exception\ReadOnlyModelException
  88.      *
  89.      * @return void
  90.      */
  91.     public function delete($con null)
  92.     {
  93.         if (!method_exists($this->getFullyQualifiedModel(), 'delete')) {
  94.             throw new ReadOnlyModelException('Cannot delete objects on a read-only model');
  95.         }
  96.         if ($con === null) {
  97.             $con $this->getWriteConnection();
  98.         }
  99.         $con->transaction(function () use ($con) {
  100.             /** @var \Propel\Runtime\ActiveRecord\ActiveRecordInterface $element */
  101.             foreach ($this as $element) {
  102.                 $element->delete($con);
  103.             }
  104.         });
  105.     }
  106.     /**
  107.      * Get an array of the primary keys of all the objects in the collection
  108.      *
  109.      * @param bool $usePrefix
  110.      *
  111.      * @return array The list of the primary keys of the collection
  112.      */
  113.     public function getPrimaryKeys($usePrefix true)
  114.     {
  115.         $ret = [];
  116.         /** @var \Propel\Runtime\ActiveRecord\ActiveRecordInterface $obj */
  117.         foreach ($this as $key => $obj) {
  118.             $key $usePrefix ? ($this->getModel() . '_' $key) : $key;
  119.             $ret[$key] = $obj->getPrimaryKey();
  120.         }
  121.         return $ret;
  122.     }
  123.     /**
  124.      * Populates the collection from an array
  125.      * Each object is populated from an array and the result is stored
  126.      * Does not empty the collection before adding the data from the array
  127.      *
  128.      * @param array $arr
  129.      *
  130.      * @return void
  131.      */
  132.     public function fromArray($arr)
  133.     {
  134.         $class $this->getFullyQualifiedModel();
  135.         foreach ($arr as $element) {
  136.             /** @var \Propel\Runtime\ActiveRecord\ActiveRecordInterface $obj */
  137.             $obj = new $class();
  138.             $obj->fromArray($element);
  139.             $this->append($obj);
  140.         }
  141.     }
  142.     /**
  143.      * Get an array representation of the collection
  144.      * Each object is turned into an array and the result is returned
  145.      *
  146.      * @param string|null $keyColumn If null, the returned array uses an incremental index.
  147.      *                                        Otherwise, the array is indexed using the specified column
  148.      * @param bool $usePrefix If true, the returned array prefixes keys
  149.      * with the model class name ('Article_0', 'Article_1', etc).
  150.      * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME,
  151.      *                                        TableMap::TYPE_CAMELNAME, TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME,
  152.      *                                        TableMap::TYPE_NUM. Defaults to TableMap::TYPE_PHPNAME.
  153.      * @param bool $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE.
  154.      * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion
  155.      *
  156.      * <code>
  157.      * $bookCollection->toArray();
  158.      * array(
  159.      *  0 => array('Id' => 123, 'Title' => 'War And Peace'),
  160.      *  1 => array('Id' => 456, 'Title' => 'Don Juan'),
  161.      * )
  162.      * $bookCollection->toArray('Id');
  163.      * array(
  164.      *  123 => array('Id' => 123, 'Title' => 'War And Peace'),
  165.      *  456 => array('Id' => 456, 'Title' => 'Don Juan'),
  166.      * )
  167.      * $bookCollection->toArray(null, true);
  168.      * array(
  169.      *  'Book_0' => array('Id' => 123, 'Title' => 'War And Peace'),
  170.      *  'Book_1' => array('Id' => 456, 'Title' => 'Don Juan'),
  171.      * )
  172.      * </code>
  173.      *
  174.      * @return array
  175.      */
  176.     public function toArray(
  177.         $keyColumn null,
  178.         $usePrefix false,
  179.         $keyType TableMap::TYPE_PHPNAME,
  180.         $includeLazyLoadColumns true,
  181.         $alreadyDumpedObjects = []
  182.     ) {
  183.         $ret = [];
  184.         $keyGetterMethod 'get' $keyColumn;
  185.         /** @var \Propel\Runtime\ActiveRecord\ActiveRecordInterface $obj */
  186.         foreach ($this->data as $key => $obj) {
  187.             $key $keyColumn === null $key $obj->$keyGetterMethod();
  188.             $key $usePrefix ? ($this->getModel() . '_' $key) : $key;
  189.             $ret[$key] = $obj->toArray($keyType$includeLazyLoadColumns$alreadyDumpedObjectstrue);
  190.         }
  191.         return $ret;
  192.     }
  193.     /**
  194.      * Get an array representation of the collection
  195.      *
  196.      * @param string|null $keyColumn If null, the returned array uses an incremental index.
  197.      *                           Otherwise, the array is indexed using the specified column
  198.      * @param bool $usePrefix If true, the returned array prefixes keys
  199.      * with the model class name ('Article_0', 'Article_1', etc).
  200.      * <code>
  201.      * $bookCollection->getArrayCopy();
  202.      * array(
  203.      * 0 => $book0,
  204.      * 1 => $book1,
  205.      * )
  206.      * $bookCollection->getArrayCopy('Id');
  207.      * array(
  208.      * 123 => $book0,
  209.      * 456 => $book1,
  210.      * )
  211.      * $bookCollection->getArrayCopy(null, true);
  212.      * array(
  213.      * 'Book_0' => $book0,
  214.      * 'Book_1' => $book1,
  215.      * )
  216.      * </code>
  217.      *
  218.      * @return array
  219.      */
  220.     public function getArrayCopy($keyColumn null$usePrefix false)
  221.     {
  222.         if ($keyColumn === null && $usePrefix === false) {
  223.             return parent::getArrayCopy();
  224.         }
  225.         $ret = [];
  226.         $keyGetterMethod 'get' $keyColumn;
  227.         foreach ($this as $key => $obj) {
  228.             $key $keyColumn === null $key $obj->$keyGetterMethod();
  229.             $key $usePrefix ? ($this->getModel() . '_' $key) : $key;
  230.             $ret[$key] = $obj;
  231.         }
  232.         return $ret;
  233.     }
  234.     /**
  235.      * Get an associative array representation of the collection
  236.      * The first parameter specifies the column to be used for the key,
  237.      * And the second for the value.
  238.      *
  239.      * <code>
  240.      *   $res = $coll->toKeyValue('Id', 'Name');
  241.      * </code>
  242.      *
  243.      * @param string $keyColumn
  244.      * @param string|null $valueColumn
  245.      *
  246.      * @return array
  247.      */
  248.     public function toKeyValue($keyColumn 'PrimaryKey'$valueColumn null)
  249.     {
  250.         $ret = [];
  251.         $keyGetterMethod 'get' $keyColumn;
  252.         $valueGetterMethod = ($valueColumn === null) ? '__toString' : ('get' $valueColumn);
  253.         foreach ($this as $obj) {
  254.             $ret[$obj->$keyGetterMethod()] = $obj->$valueGetterMethod();
  255.         }
  256.         return $ret;
  257.     }
  258.     /**
  259.      * Get an associative array representation of the collection.
  260.      * The first parameter specifies the column to be used for the key.
  261.      *
  262.      * <code>
  263.      *   $res = $userCollection->toKeyIndex('Name');
  264.      *
  265.      *   $res = array(
  266.      *       'peter' => class User #1 {$name => 'peter', ...},
  267.      *       'hans' => class User #2 {$name => 'hans', ...},
  268.      *       ...
  269.      *   )
  270.      * </code>
  271.      *
  272.      * @param string $keyColumn
  273.      *
  274.      * @return array
  275.      */
  276.     public function toKeyIndex($keyColumn 'PrimaryKey')
  277.     {
  278.         $ret = [];
  279.         $keyGetterMethod 'get' ucfirst($keyColumn);
  280.         foreach ($this as $obj) {
  281.             $ret[$obj->$keyGetterMethod()] = $obj;
  282.         }
  283.         return $ret;
  284.     }
  285.     /**
  286.      * Get an array representation of the column.
  287.      *
  288.      * <code>
  289.      *   $res = $userCollection->toKeyIndex('Name');
  290.      *
  291.      *   $res = array(
  292.      *       'peter',
  293.      *       'hans',
  294.      *       ...
  295.      *   )
  296.      * </code>
  297.      *
  298.      * @param string $columnName
  299.      *
  300.      * @return array
  301.      */
  302.     public function getColumnValues($columnName 'PrimaryKey')
  303.     {
  304.         $ret = [];
  305.         $keyGetterMethod 'get' ucfirst($columnName);
  306.         foreach ($this as $obj) {
  307.             $ret[] = $obj->$keyGetterMethod();
  308.         }
  309.         return $ret;
  310.     }
  311.     /**
  312.      * Makes an additional query to populate the objects related to the collection objects
  313.      * by a certain relation
  314.      *
  315.      * @param string $relation Relation name (e.g. 'Book')
  316.      * @param \Propel\Runtime\ActiveQuery\Criteria|null $criteria Optional Criteria object to filter the related object collection
  317.      * @param \Propel\Runtime\Connection\ConnectionInterface|null $con Optional connection object
  318.      *
  319.      * @throws \Propel\Runtime\Exception\RuntimeException
  320.      * @throws \Propel\Runtime\Collection\Exception\UnsupportedRelationException
  321.      *
  322.      * @return \Propel\Runtime\Collection\ObjectCollection The list of related objects
  323.      */
  324.     public function populateRelation($relation$criteria null$con null)
  325.     {
  326.         if (!Propel::isInstancePoolingEnabled()) {
  327.             throw new RuntimeException(__METHOD__ ' needs instance pooling to be enabled prior to populating the collection');
  328.         }
  329.         $relationMap $this->getFormatter()->getTableMap()->getRelation($relation);
  330.         if ($this->isEmpty()) {
  331.             // save a useless query and return an empty collection
  332.             $relationClassName $relationMap->getRightTable()->getClassName();
  333.             $collectionClassName $relationMap->getRightTable()->getCollectionClassName();
  334.             $coll = new $collectionClassName();
  335.             $coll->setModel($relationClassName);
  336.             $coll->setFormatter($this->getFormatter());
  337.             return $coll;
  338.         }
  339.         $symRelationMap $relationMap->getSymmetricalRelation();
  340.         $query PropelQuery::from($relationMap->getRightTable()->getClassName());
  341.         if ($criteria !== null) {
  342.             $query->mergeWith($criteria);
  343.         }
  344.         // query the db for the related objects
  345.         $filterMethod 'filterBy' $symRelationMap->getName();
  346.         $relatedObjects $query
  347.             ->$filterMethod($this)
  348.             ->find($con);
  349.         if ($relationMap->getType() === RelationMap::ONE_TO_MANY) {
  350.             // initialize the embedded collections of the main objects
  351.             $relationName $relationMap->getName();
  352.             $resetPartialStatusMethod 'resetPartial' $relationMap->getPluralName();
  353.             foreach ($this as $mainObj) {
  354.                 $mainObj->initRelation($relationName);
  355.                 $mainObj->$resetPartialStatusMethod(false);
  356.             }
  357.             // associate the related objects to the main objects
  358.             $getMethod 'get' $symRelationMap->getName();
  359.             $addMethod 'add' $relationName;
  360.             foreach ($relatedObjects as $object) {
  361.                 $mainObj $object->$getMethod(); // instance pool is used here to avoid a query
  362.                 $mainObj->$addMethod($object);
  363.             }
  364.         } elseif ($relationMap->getType() === RelationMap::MANY_TO_ONE) {
  365.             // nothing to do; the instance pool will catch all calls to getRelatedObject()
  366.             // and return the object in memory
  367.         } else {
  368.             throw new UnsupportedRelationException(__METHOD__ ' does not support this relation type');
  369.         }
  370.         return $relatedObjects;
  371.     }
  372.     /**
  373.      * @inheritDoc
  374.      */
  375.     public function search($element)
  376.     {
  377.         if (isset($this->indexSplHash[$splHash spl_object_hash($element)])) {
  378.             return $this->index[$this->indexSplHash[$splHash]];
  379.         }
  380.         $hashCode $this->getHashCode($element);
  381.         if (isset($this->index[$hashCode])) {
  382.             return $this->index[$hashCode];
  383.         }
  384.         return false;
  385.     }
  386.     /**
  387.      * @return void
  388.      */
  389.     protected function rebuildIndex()
  390.     {
  391.         $this->index = [];
  392.         $this->indexSplHash = [];
  393.         foreach ($this->data as $idx => $value) {
  394.             $hashCode $this->getHashCode($value);
  395.             $this->index[$hashCode] = $idx;
  396.             $this->indexSplHash[spl_object_hash($value)] = $hashCode;
  397.         }
  398.     }
  399.     /**
  400.      * @param mixed $offset
  401.      *
  402.      * @return void
  403.      */
  404.     public function offsetUnset($offset): void
  405.     {
  406.         if (isset($this->data[$offset])) {
  407.             if (is_object($this->data[$offset])) {
  408.                 unset($this->indexSplHash[spl_object_hash($this->data[$offset])]);
  409.                 unset($this->index[$this->getHashCode($this->data[$offset])]);
  410.             }
  411.             unset($this->data[$offset]);
  412.         }
  413.     }
  414.     /**
  415.      * @param mixed $element
  416.      *
  417.      * @return void
  418.      */
  419.     public function removeObject($element)
  420.     {
  421.         if (($pos $this->search($element)) !== false) {
  422.             $this->remove($pos);
  423.         }
  424.     }
  425.     /**
  426.      * @param mixed $value
  427.      *
  428.      * @return void
  429.      */
  430.     public function append($value)
  431.     {
  432.         if (!is_object($value)) {
  433.             parent::append($value);
  434.             return;
  435.         }
  436.         $this->data[] = $value;
  437.         end($this->data);
  438.         $pos key($this->data);
  439.         $hashCode $this->getHashCode($value);
  440.         $this->index[$hashCode] = $pos;
  441.         $this->indexSplHash[spl_object_hash($value)] = $hashCode;
  442.     }
  443.     /**
  444.      * @param mixed $offset
  445.      * @param mixed $value
  446.      *
  447.      * @return void
  448.      */
  449.     public function offsetSet($offset$value): void
  450.     {
  451.         if (!is_object($value)) {
  452.             parent::offsetSet($offset$value);
  453.             return;
  454.         }
  455.         $hashCode $this->getHashCode($value);
  456.         if ($offset === null) {
  457.             $this->data[] = $value;
  458.             end($this->data);
  459.             $pos key($this->data);
  460.             $this->index[$hashCode] = $pos;
  461.             $this->indexSplHash[spl_object_hash($value)] = $hashCode;
  462.         } else {
  463.             if (isset($this->data[$offset])) {
  464.                 unset($this->indexSplHash[spl_object_hash($this->data[$offset])]);
  465.                 unset($this->index[$this->getHashCode($this->data[$offset])]);
  466.             }
  467.             $this->index[$hashCode] = $offset;
  468.             $this->indexSplHash[spl_object_hash($value)] = $hashCode;
  469.             $this->data[$offset] = $value;
  470.         }
  471.     }
  472.     /**
  473.      * @inheritDoc
  474.      */
  475.     public function contains($element)
  476.     {
  477.         if (!is_object($element)) {
  478.             return parent::contains($element);
  479.         }
  480.         return isset($this->indexSplHash[spl_object_hash($element)]) || isset($this->index[$this->getHashCode($element)]);
  481.     }
  482.     /**
  483.      * Returns the result of $object->hashCode() if available or uses spl_object_hash($object).
  484.      *
  485.      * @param mixed $object
  486.      *
  487.      * @return string
  488.      */
  489.     protected function getHashCode($object)
  490.     {
  491.         if (is_object($object) && is_callable([$object'hashCode'])) {
  492.             return $object->hashCode();
  493.         }
  494.         return spl_object_hash($object);
  495.     }
  496. }