Hey! My name is Pavel and I am doing backend development. Today we will look at collections in Magento 2 (hereinafter referred to as M2). Despite the seeming simplicity of implementation and intuitive purpose, this essence is fraught with several unobvious pitfalls that affect the performance, and sometimes the very possibility of the code.
, , .
!
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
, , . ?
, 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:
. load()
, foreach
( , ArrayAccess
):
$collection = $this->whiteRabbitCollectionFactory->create();
$name = 'White Rabbit';
$collection->addFieldToFilter('name', $name);
foreach ($this->collection as $rabbit) {
//stop point
}
. !
, 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')
:
$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))
, :
, , . clear()
, , load()
:
. load()
, , . clear()
load()
foreach
:
. , 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. , , .
. . !