Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
EntityGenerator.php
Go to the documentation of this file.
1 <?php
8 
11 
16 {
18 
19  const SKIP_ENTITY_ID_BINDING = 'skip_entity_id_binding';
20 
30  private $customTableMap;
31 
37  private $entityType;
38 
42  private $sqlCollector;
43 
47  private $resourceConnection;
48 
52  private $attributeLoader;
53 
57  private $attributes;
58 
62  private $connection;
63 
67  private $tableToEntityIdMap;
68 
72  private $entityTable;
73 
79  private $primaryEntityIdTables;
80 
84  private $metadataPool;
85 
89  private $entityMetadata;
90 
94  private $sequenceRegistry;
95 
99  private $isMappingInitialized = false;
100 
104  private $bunchSize;
105 
116  public function __construct(
117  \Magento\Setup\Model\FixtureGenerator\SqlCollector $sqlCollector,
118  \Magento\Eav\Model\ResourceModel\AttributeLoader $attributeLoader,
119  \Magento\Framework\App\ResourceConnection $resourceConnection,
120  \Magento\Framework\EntityManager\MetadataPool $metadataPool,
121  \Magento\Framework\EntityManager\Sequence\SequenceRegistry $sequenceRegistry,
122  $entityType,
123  $customTableMap = [],
124  $bunchSize = self::SQL_DEFAULT_BUNCH_AMOUNT
125  ) {
126  $this->sqlCollector = $sqlCollector;
127  $this->resourceConnection = $resourceConnection;
128  $this->attributeLoader = $attributeLoader;
129  $this->metadataPool = $metadataPool;
130  $this->sequenceRegistry = $sequenceRegistry;
131  $this->customTableMap = $customTableMap;
132  $this->entityType = $entityType;
133  $this->bunchSize = (int)$bunchSize;
134  }
135 
145  public function generate(TemplateEntityGeneratorInterface $entityGenerator, $entitiesAmount, callable $fixture)
146  {
147  $this->getConnection()->beginTransaction();
148  try {
149  $this->sqlCollector->enable();
150  $entity = $entityGenerator->generateEntity();
151  $this->sqlCollector->disable();
152  $entity->delete();
153  $this->getConnection()->commit();
154  } catch (\Exception $e) {
155  $this->getConnection()->rollBack();
156  throw new LocalizedException(
157  __('Cannot generate entities - error occurred during template creation: %1', $e->getMessage()),
158  $e
159  );
160  }
161 
162  $map = [];
163  $processed = 0;
164  $entitiesAmount = (int)$entitiesAmount;
165  gc_disable();
166  for ($entityNumber = 0; $entityNumber < $entitiesAmount; $entityNumber++) {
167  $processed++;
168  $map = array_merge_recursive($map, $this->getSqlQueries($entity, $entityNumber, $fixture));
169 
170  if ($processed % $this->bunchSize === 0 || $entityNumber === ($entitiesAmount - 1)) {
171  $this->saveEntities($map);
172  }
173  }
174  gc_enable();
175  }
176 
185  private function getSqlQueries($entity, $entityNumber, callable $fixtureMap)
186  {
187  $metadata = $this->getEntityMetadata();
188  $this->initializeMapping();
189 
190  $entityId = $entity->getData($metadata->getIdentifierField()) + $entityNumber;
191  $entityLinkId = $entity->getData($metadata->getLinkField()) + $entityNumber;
192  $fixtureMap = $fixtureMap($entityId, $entityNumber);
193 
194  $sql = [];
195  foreach ($this->sqlCollector->getSql() as $pattern) {
196  list($binds, $table) = $pattern;
197 
198  if (!isset($sql[$table])) {
199  $sql[$table] = [];
200  }
201 
202  foreach ($binds as &$bind) {
203  if ($table === $this->getEntityTable()) {
204  $bind[$metadata->getLinkField()] = $entityLinkId;
205  $bind[$metadata->getIdentifierField()] = $entityId;
206  }
207 
208  if ($bind) {
209  $this->setNewBindValue($entityId, $entityNumber, $table, $bind, $fixtureMap);
210  }
211  if (self::SKIP_ENTITY_ID_BINDING === $this->getEntityIdField($table)) {
212  continue;
213  }
214  if ($this->getEntityIdField($table) === $metadata->getLinkField()) {
215  $bind[$this->getEntityIdField($table)] = $entityLinkId;
216  } else {
217  $bind[$this->getEntityIdField($table)] = $entityId;
218  }
219  }
220 
221  $binds = $this->bindWithCustomHandler($table, $entityId, $entityNumber, $fixtureMap, $binds);
222  $sql[$table] = array_merge($sql[$table], $binds);
223  }
224 
225  return $sql;
226  }
227 
238  private function bindWithCustomHandler($table, $entityId, $entityNumber, $fixtureMap, $binds)
239  {
240  if (isset($this->customTableMap[$table]['handler'])
241  && is_callable($this->customTableMap[$table]['handler'])
242  ) {
243  $binds = $this->customTableMap[$table]['handler']($entityId, $entityNumber, $fixtureMap, $binds);
244  }
245 
246  return $binds;
247  }
248 
256  private function saveEntities(array &$map)
257  {
258  $this->getConnection()->beginTransaction();
259  try {
260  foreach ($map as $table => $data) {
261  $this->getConnection()->insertMultiple($table, $data);
262  }
263  $this->getConnection()->commit();
264  } catch (\Exception $e) {
265  $this->getConnection()->rollBack();
266  throw new LocalizedException(
267  __('Cannot save entity. Error occurred: %1', $e->getMessage()),
268  $e
269  );
270  }
271 
272  $map = [];
273  }
274 
278  private function getConnection()
279  {
280  if (null === $this->connection) {
281  $this->connection = $this->resourceConnection->getConnection();
282  }
283 
284  return $this->connection;
285  }
286 
290  private function getEntityMetadata()
291  {
292  if (null === $this->entityMetadata) {
293  $this->entityMetadata = $this->metadataPool->getMetadata($this->entityType);
294  }
295 
296  return $this->entityMetadata;
297  }
298 
304  private function getEntityTable()
305  {
306  if (null === $this->entityTable) {
307  $this->entityTable = $this->getEntityMetadata()->getEntityTable();
308  }
309 
310  return $this->entityTable;
311  }
312 
321  private function getEntityIdField($table)
322  {
323  if (!isset($this->tableToEntityIdMap[$table])) {
324  $foreignKey = null;
325  foreach ($this->primaryEntityIdTables as $primaryTable) {
326  $foreignKey = array_filter(
327  $this->getConnection()->getForeignKeys($table),
328  function ($ddl) use ($primaryTable) {
329  return $ddl['REF_TABLE_NAME'] === $primaryTable
330  && $ddl['REF_COLUMN_NAME'] === $this->getEntityIdField($primaryTable);
331  }
332  );
333  if ($foreignKey) {
334  break;
335  }
336  }
337  if (!$foreignKey) {
338  throw new ValidatorException(
339  __('The entity ID field for the "%1" table wasn\'t found. Verify the field and try again.', $table)
340  );
341  }
342  $this->tableToEntityIdMap[$table] = current($foreignKey)['COLUMN_NAME'];
343  }
344 
345  return $this->tableToEntityIdMap[$table];
346  }
347 
354  private function initializeMapping()
355  {
356  if (!$this->isMappingInitialized) {
357  $this->isMappingInitialized = true;
358 
359  $this->initCustomTables();
360 
361  $this->primaryEntityIdTables = [
362  $this->getEntityMetadata()->getEntityTable()
363  ];
364  $entitySequence = $this->sequenceRegistry->retrieve($this->entityType);
365  if (isset($entitySequence['sequenceTable'])) {
366  $this->primaryEntityIdTables[] = $this->resourceConnection->getTableName(
367  $entitySequence['sequenceTable']
368  );
369  }
370 
371  foreach ($this->primaryEntityIdTables as $table) {
372  $ddl = array_filter(
373  $this->getConnection()->describeTable($table),
374  function ($data) {
375  return $data['PRIMARY'] === true;
376  }
377  );
378  if (!$ddl) {
379  throw new ValidatorException(
380  __('The primary key for the "%1" table wasn\'t found. Verify the key and try again.', $table)
381  );
382  }
383  $this->tableToEntityIdMap[$table] = current($ddl)['COLUMN_NAME'];
384  }
385  }
386  }
387 
393  private function initCustomTables()
394  {
395  $customTableData = [
396  'entity_id_field' => null,
397  'handler' => null,
398  'fields' => [],
399  ];
400  $customTableMap = [];
401  foreach ($this->customTableMap as $table => $data) {
402  $table = $this->resourceConnection->getTableName($table);
403  $data = array_merge($customTableData, $data);
404  $customTableMap[$table] = $data;
405  if ($data['entity_id_field']) {
406  $this->tableToEntityIdMap[$table] = $data['entity_id_field'];
407  }
408  }
409  $this->customTableMap = $customTableMap;
410  }
411 
417  private function getAttributesMetadata()
418  {
419  if (null === $this->attributes) {
420  foreach ($this->attributeLoader->getAttributes($this->entityType) as $attribute) {
421  if ($attribute->isStatic()) {
422  continue;
423  }
424  $this->attributes[$attribute->getBackendTable()][$attribute->getAttributeCode()] = [
425  'value_field' => 'value',
426  'link_field' => 'attribute_id',
427  'attribute_id' => $attribute->getAttributeId(),
428  ];
429  }
430  }
431 
432  return $this->attributes;
433  }
434 
446  private function setNewBindValue($entityId, $entityNumber, $table, array &$bind, array $fixtureMap)
447  {
448  $attributes = $this->getAttributesMetadata();
449  if (isset($attributes[$table])) {
450  // Process binding new value for eav attributes
451  foreach ($fixtureMap as $fixtureField => $fixture) {
452  if (!isset($attributes[$table][$fixtureField])) {
453  continue;
454  }
455  $attribute = $attributes[$table][$fixtureField];
456 
457  if (isset($bind[$attribute['link_field']])
458  && $bind[$attribute['link_field']] === $attribute[$attribute['link_field']]
459  ) {
460  $bind[$attribute['value_field']] = $this->getBindValue($fixture, $entityId, $entityNumber);
461  break;
462  }
463  }
464  } elseif (isset($this->customTableMap[$table])) {
465  foreach ($this->customTableMap[$table]['fields'] as $field => $fixtureField) {
466  $bind[$field] = $this->getFixtureValue($fixtureField, $entityId, $entityNumber, $fixtureMap);
467  }
468  }
469  }
470 
478  private function getFixtureValue($fixtureField, $entityId, $entityNumber, array $fixtureMap)
479  {
480  $fixture = isset($fixtureMap[$fixtureField]) ? $fixtureMap[$fixtureField] : null;
481  return $fixture ? $this->getBindValue($fixture, $entityId, $entityNumber) : '';
482  }
483 
490  private function getBindValue($fixture, $entityId, $entityNumber)
491  {
492  $bindValue = is_callable($fixture)
493  ? call_user_func($fixture, $entityId, $entityNumber)
494  : $fixture;
495 
496  return is_array($bindValue) ? array_shift($bindValue) : $bindValue;
497  }
498 }
__construct(\Magento\Setup\Model\FixtureGenerator\SqlCollector $sqlCollector, \Magento\Eav\Model\ResourceModel\AttributeLoader $attributeLoader, \Magento\Framework\App\ResourceConnection $resourceConnection, \Magento\Framework\EntityManager\MetadataPool $metadataPool, \Magento\Framework\EntityManager\Sequence\SequenceRegistry $sequenceRegistry, $entityType, $customTableMap=[], $bunchSize=self::SQL_DEFAULT_BUNCH_AMOUNT)
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$pattern
Definition: website.php:22
__()
Definition: __.php:13
$entity
Definition: element.phtml:22
$table
Definition: trigger.php:14
generate(TemplateEntityGeneratorInterface $entityGenerator, $entitiesAmount, callable $fixture)