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