Datos no obvios sobre colecciones en Magento 2

¡Oye! Mi nombre es Pavel y estoy haciendo desarrollo de backend. Hoy veremos las colecciones en Magento 2 (en lo sucesivo, M2). A pesar de la aparente simplicidad de implementación y el propósito intuitivo, esta esencia está plagada de varios obstáculos no obvios que afectan el rendimiento y, a veces, la capacidad misma del código para funcionar. 





, , . 





!





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



, , . ?





Colección descargada en 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:





Colección cargada usando el método load ()
load()

. load()



, foreach



( , ArrayAccess



):





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



. !





Colección cargada al acceder a elementos de colección

, 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')
      
      



Colección cargada con primer filtro

:





$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))
      
      



, :





La colección cargada no ha cambiado

, , . clear()



, , load()



:





Colección recargada con nuevo filtro

. load()



, , . clear()



load()



foreach



:





Al acceder a elementos, la colección cargada no ha cambiado

. , 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