Nicht offensichtliche Fakten über Sammlungen in Magento 2

Hallo! Mein Name ist Pavel und ich mache Backend-Entwicklung. Heute werden wir uns Sammlungen in Magento 2 (im Folgenden als M2 bezeichnet) ansehen. Trotz der scheinbaren Einfachheit der Implementierung und des intuitiven Zwecks ist diese Essenz mit mehreren nicht offensichtlichen Fallstricken behaftet, die sich auf die Leistung und manchmal auf die Funktionsfähigkeit des Codes auswirken. 





, , . 





!





M2

, , 2 — -, , : , , .





- , :





<?php
declare(strict_types=1);

namespace RSHB\WhiteRabbit\Model\ResourceModel\WhiteRabbit;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use RSHB\WhiteRabbit\Model\ResourceModel\WhiteRabbit as WhiteRabbitResource;
use RSHB\WhiteRabbit\Model\WhiteRabbit as WhiteRabbitModel;

/**
 * Class Collection
 * @package RSHB\WhiteRabbit\Model\ResourceModel\WhiteRabbit
 */
class Collection extends AbstractCollection
{
    /**
     * {@inheritDoc}
     */
    protected function _construct()
    {
        $this->_init(
            WhiteRabbitModel::class,
            WhiteRabbitResource::class
        );
    }
}

      
      



, -, . . , .





, :





$collection = $this->whiteRabbitCollectionFactory->create();
      
      



:





$collection->addFieldToFilter('name', $name);
      
      



xdebug. , _items



, , . ?





Entladene Sammlung in xdebug
xdebug

, M2-. sql . , , , — ORM, . , , :





$collection->getSelect()->__toString()
      
      



:





SELECT main_table. FROM rshb_white_rabbit AS main_table WHERE (name = 'White Rabbit')
      
      



, WHERE



. SELECT



_initSelect()



( ).





, , , .





: : . SQL , .





, — load()



. , xdebug:





Geladene Sammlung mit der Methode load ()
load()

. load()



, foreach



( , ArrayAccess



):





$collection = $this->whiteRabbitCollectionFactory->create();
$name = 'White Rabbit';
$collection->addFieldToFilter('name', $name);
foreach ($this->collection as $rabbit) {
    //stop point
}
      
      



. !





Geladene Sammlung beim Zugriff auf Sammlungselemente

, load()



? , . , load()



, .





: . 





. ,





:





$collection = $this->whiteRabbitCollectionFactory->create();
$name = '%Rabbit';
$collection->addFieldToFilter('name', [‘like’ => $name]);
$collection->load();
//stop point 1
      
      



SELECT main_table.* FROM rshb_white_rabbit AS main_table WHERE (name LIKE '%Rabbit')
      
      



Geladene Sammlung mit erstem Filter

:





$ids = [1, 2];
$collection->addFieldToFilter('id', [‘in’ $ids]);
//stop point 2
$collection->clear();
$collection->load();
      
      



, :





SELECT `main_table`.* FROM `rshb_white_rabbit` AS `main_table` WHERE (`name` LIKE '%Rabbit') AND (`id` IN (1, 2))
      
      



, :





Die geladene Sammlung hat sich nicht geändert

, , . clear()



, , load()



:





Sammlung mit neuem Filter neu geladen

. load()



, , . clear()



load()



foreach



:





Beim Zugriff auf Elemente hat sich die geladene Sammlung nicht geändert

. , clear()



, .





:





if (count($collection)) {
//do something…
}
      
      



, , , count ( ArrayAccess



Countable



, ). .  





, . count



, .. . ,   - , , count



$collection->getSize()



. :





SELECT COUNT(*) FROM `rshb_white_rabbit` AS `main_table` WHERE (`name` LIKE '%Rabbit') AND (`id` IN (1, 2))
      
      



.





, , .





, , , , COUNT



:





If ($collection->getSize()) {
  foreach ($collection as $item) {
  	//Do something
  }
}
      
      



foreach ($collection as $item) {
	//do nothing if collection is empty
}
      
      



, , . , , , , , - .





:





$collection = $this->collectionFactory->create();
$name = '%Rabbit';
$collection->addFieldToFilter('name', [‘like’ => $name]);
$item = $collection->getFirstItem();
      
      



:





  • ;





  • ( , ).





, : , , , : 





SELECT main_table.* FROM rshb_white_rabbit AS main_table WHERE (name LIKE '%Rabbit')
      
      



, , :





$collection = $this->collectionFactory->create();
$name = '%Rabbit';
$collection->addFieldToFilter('name', [‘like’ => $name]);
$collection->addOrder(‘name’, ASC);
$collection->setPageSize(1);
$item = $collection->getFirstItem();
      
      



SELECT `main_table`.* FROM `rshb_white_rabbit` AS `main_table` WHERE (`name` LIKE '%Rabbit') ORDER BY name ASC LIMIT 1
      
      



AND OR condition

:





$collection = $this->whiteRabbitCollectionFactory->create();
$name = '%Rabbit';
$collection->addFieldToFilter('name', [‘like’ => $name]);
$ids = [1, 2];
$collection->addFieldToFilter('id', [‘in’ $ids]);
      
      



SQL-:





SELECT `main_table`.* FROM `rshb_white_rabbit` AS `main_table` WHERE (`name` LIKE '%Rabbit') AND (`id` IN (1, 2))
      
      



, AND



.





OR



, :





$collection = $this->whiteRabbitCollectionFactory->create();
$name = '%Rabbit';
$ids = [1, 2];
$collection->addFieldToFilter(
    ['name', 'id'],
    [
        ['like' => $name],
        ['in' => $ids]
    ]
);
      
      



SQL-:





SELECT `main_table`.* FROM `rshb_white_rabbit` AS `main_table` WHERE ((`name` LIKE '%Rabbit') OR (`id` IN (1, 2)))
      
      



, .





, , :





PHP Fatal error: Allowed memory size of XXXX bytes exhausted (tried to allocate XXXX bytes) in vendor/magento/zendframework1/library/Zend/Db/Statement/Pdo.php on line 228
      
      



.





  • , :





$collection = $this->collectionFactory->create();
$name = '%Rabbit';
$lastId = 500;
$collection->addFieldToFilter('name', [‘like’ => $name]);
$collection->addFieldToFilter('id', [‘gt’ => $lastId]);
$collection->addOrder(‘id’);
$collection->setPageSize(500);
      
      



.





  • walk()



    Magento\Framework\Model\ResourceModel\Iterator



    :





public function doAnything()
{
	...
  $this->iterator->walk(
    $collection->getSelect(),
    [[$this, 'callback']]
  );
}

public function callback($args)
{
	//do something
}
      
      



, ( ).





, _initSelect()



. . join` :





<?php
declare(strict_types=1);

namespace RSHB\WhiteRabbit\Model\ResourceModel\WhiteRabbit;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use RSHB\WhiteRabbit\Model\ResourceModel\WhiteRabbit as WhiteRabbitResource;
use RSHB\WhiteRabbit\Model\WhiteRabbit as WhiteRabbitModel;

/**
 * Class Collection
 * @package RSHB\WhiteRabbit\Model\ResourceModel\WhiteRabbit
 */
class Collection extends AbstractCollection
{
    /**
     * {@inheritDoc}
     */
    protected function _construct()
    {
        $this->_init(
            WhiteRabbitModel::class,
            WhiteRabbitResource::class
        );
    }

    /**
     * @return Collection|void
     */
    protected function _initSelect()
    {
        parent::_initSelect();

        $this->getSelect()->join(
                ['another_white_rabbit' => 'rshb_another_white_rabbit'],
                'main_table.id = another_white_rabbit.white_rabbit_id',
                ['another_name' => 'another_white_rabbit.name']
            );

        return $this;
    }
}
      
      



, .





, .





  • getSize()



    count()



    ( , ).





  • (setPageSize()



    ) , .





  • , :





// :
$collection->addFieldToSelect('*');
//   :
$collection->addFieldToSelect(['first', 'second', 'third']);
//,       :
$collection->getFieldValues('somefield');
      
      



  • , .





  • , . Connection



    :





/** @var \Magento\Framework\App\ResourceConnection $connection **/
$connection = $this->connection->getConnection();
$tableName = $this->connection->getTableName('rshbwhite_rabbit’);
$sql = "SELECT * FROM $tableName";
$result = $connection->fetchAll($sql);
      
      



, — .





2. , , .





. . !








All Articles