Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Migration.php
Go to the documentation of this file.
1 <?php
7 
11 
20 class Migration
21 {
25  const FIELD_CONTENT_TYPE_PLAIN = 'plain';
26 
27  const FIELD_CONTENT_TYPE_XML = 'xml';
28 
29  const FIELD_CONTENT_TYPE_WIKI = 'wiki';
30 
31  const FIELD_CONTENT_TYPE_SERIALIZED = 'serialized';
32 
38  const ENTITY_TYPE_MODEL = 'Model';
39 
40  const ENTITY_TYPE_BLOCK = 'Block';
41 
42  const ENTITY_TYPE_RESOURCE = 'Model_Resource';
43 
49  const SERIALIZED_REPLACE_PATTERN = 's:%d:"%s"';
50 
55 
62 
68  protected $_rowsPerPage = 100;
69 
83  protected $_replaceRules = [];
84 
94  protected $_aliasesMap;
95 
101  protected $_replacePatterns = [];
102 
108  protected $_pathToMapFile;
109 
116 
120  protected $_directory;
121 
125  protected $_migrationData;
126 
130  private $setup;
131 
135  private $serializer;
136 
146  public function __construct(
149  MigrationData $migrationData,
150  $confPathToMapFile,
151  $compositeModules = [],
152  \Magento\Framework\Serialize\Serializer\Json $serializer = null
153  ) {
154  $this->_directory = $filesystem->getDirectoryRead(DirectoryList::ROOT);
155  $this->_pathToMapFile = $confPathToMapFile;
156  $this->_migrationData = $migrationData;
157  $this->_replacePatterns = [
158  self::FIELD_CONTENT_TYPE_WIKI => $this->_migrationData->getWikiFindPattern(),
159  self::FIELD_CONTENT_TYPE_XML => $this->_migrationData->getXmlFindPattern(),
160  ];
161  $this->_compositeModules = $compositeModules;
162  $this->setup = $setup;
163  $this->serializer = $serializer?: \Magento\Framework\App\ObjectManager::getInstance()
164  ->get(\Magento\Framework\Serialize\Serializer\Json::class);
165  }
166 
178  public function appendClassAliasReplace(
179  $tableName,
180  $fieldName,
181  $entityType = '',
182  $fieldContentType = self::FIELD_CONTENT_TYPE_PLAIN,
183  array $primaryKeyFields = [],
184  $additionalWhere = ''
185  ) {
186  if (!isset($this->_replaceRules[$tableName])) {
187  $this->_replaceRules[$tableName] = [];
188  }
189 
190  if (!isset($this->_replaceRules[$tableName][$fieldName])) {
191  $this->_replaceRules[$tableName][$fieldName] = [
192  'entity_type' => $entityType,
193  'content_type' => $fieldContentType,
194  'pk_fields' => $primaryKeyFields,
195  'additional_where' => $additionalWhere,
196  ];
197  }
198  }
199 
205  public function doUpdateClassAliases()
206  {
207  foreach ($this->_replaceRules as $tableName => $tableRules) {
208  $this->_updateClassAliasesInTable($tableName, $tableRules);
209  }
210  }
211 
219  protected function _updateClassAliasesInTable($tableName, array $tableRules)
220  {
221  foreach ($tableRules as $fieldName => $fieldRule) {
222  $pagesCount = ceil(
223  $this->_getRowsCount($tableName, $fieldName, $fieldRule['additional_where']) / $this->_rowsPerPage
224  );
225 
226  for ($page = 1; $page <= $pagesCount; $page++) {
227  $this->_applyFieldRule($tableName, $fieldName, $fieldRule, $page);
228  }
229  }
230  }
231 
240  protected function _getRowsCount($tableName, $fieldName, $additionalWhere = '')
241  {
242  $connection = $this->setup->getConnection();
243 
244  $query = $connection->select()->from(
245  $this->setup->getTable($tableName),
246  ['rows_count' => new \Zend_Db_Expr('COUNT(*)')]
247  )->where(
248  $fieldName . ' IS NOT NULL'
249  );
250 
251  if (!empty($additionalWhere)) {
252  $query->where($additionalWhere);
253  }
254 
255  return (int)$connection->fetchOne($query);
256  }
257 
267  protected function _applyFieldRule($tableName, $fieldName, array $fieldRule, $currentPage = 0)
268  {
269  $fieldsToSelect = [$fieldName];
270  if (!empty($fieldRule['pk_fields'])) {
271  $fieldsToSelect = array_merge($fieldsToSelect, $fieldRule['pk_fields']);
272  }
273  $tableData = $this->_getTableData(
274  $tableName,
275  $fieldName,
276  $fieldsToSelect,
277  $fieldRule['additional_where'],
278  $currentPage
279  );
280 
281  $fieldReplacements = [];
282  foreach ($tableData as $rowData) {
283  $replacement = $this->_getReplacement(
284  $rowData[$fieldName],
285  $fieldRule['content_type'],
286  $fieldRule['entity_type']
287  );
288  if ($replacement !== $rowData[$fieldName]) {
289  $fieldReplacement = ['to' => $replacement];
290  if (empty($fieldRule['pk_fields'])) {
291  $fieldReplacement['where_fields'] = [$fieldName => $rowData[$fieldName]];
292  } else {
293  $fieldReplacement['where_fields'] = [];
294  foreach ($fieldRule['pk_fields'] as $pkField) {
295  $fieldReplacement['where_fields'][$pkField] = $rowData[$pkField];
296  }
297  }
298  $fieldReplacements[] = $fieldReplacement;
299  }
300  }
301 
302  $this->_updateRowsData($tableName, $fieldName, $fieldReplacements);
303  }
304 
313  protected function _updateRowsData($tableName, $fieldName, array $fieldReplacements)
314  {
315  if (count($fieldReplacements) > 0) {
316  $connection = $this->setup->getConnection();
317 
318  foreach ($fieldReplacements as $fieldReplacement) {
319  $where = [];
320  foreach ($fieldReplacement['where_fields'] as $whereFieldName => $value) {
321  $where[$connection->quoteIdentifier($whereFieldName) . ' = ?'] = $value;
322  }
323  $connection->update(
324  $this->setup->getTable($tableName),
325  [$fieldName => $fieldReplacement['to']],
326  $where
327  );
328  }
329  }
330  }
331 
342  protected function _getTableData(
343  $tableName,
344  $fieldName,
345  array $fieldsToSelect,
346  $additionalWhere = '',
347  $currPage = 0
348  ) {
349  $connection = $this->setup->getConnection();
350 
351  $query = $connection->select()->from(
352  $this->setup->getTable($tableName),
353  $fieldsToSelect
354  )->where(
355  $fieldName . ' IS NOT NULL'
356  );
357 
358  if (!empty($additionalWhere)) {
359  $query->where($additionalWhere);
360  }
361 
362  if ($currPage) {
363  $query->limitPage($currPage, $this->_rowsPerPage);
364  }
365 
366  return $connection->fetchAll($query);
367  }
368 
377  protected function _getReplacement($data, $contentType, $entityType = '')
378  {
379  switch ($contentType) {
382  break;
383  // wiki and xml content types use the same replacement method
386  $data = $this->_getPatternReplacement($data, $contentType, $entityType);
387  break;
389  default:
391  break;
392  }
393 
394  return $data;
395  }
396 
405  {
406  if ($this->_isFactoryName($alias)) {
408  return $className;
409  }
410 
411  list($module, $name) = $this->_getModuleName($alias);
412 
413  if (!empty($entityType)) {
414  $className = $this->_getClassName($module, $entityType, $name);
415  $properEntityType = $entityType;
416  } else {
417  // Try to find appropriate class name for all entity types
418  $className = '';
419  $properEntityType = '';
420  foreach ($this->_entityTypes as $entityType) {
421  if (empty($className)) {
422  $className = $this->_getClassName($module, $entityType, $name);
423  $properEntityType = $entityType;
424  } else {
425  // If was found more than one match - alias cannot be replaced
426  return '';
427  }
428  }
429  }
430  $this->_pushToMap($properEntityType, $alias, $className);
431  return $className;
432  }
433 
434  return '';
435  }
436 
444  protected function _getModelReplacement($data, $entityType = '')
445  {
446  if (preg_match($this->_migrationData->getPlainFindPattern(), $data, $matches)) {
447  $classAlias = $matches['alias'];
448  $className = $this->_getCorrespondingClassName($classAlias, $entityType);
449  if ($className) {
450  return str_replace($classAlias, $className, $data);
451  }
452  }
453 
455  if (!empty($className)) {
456  return $className;
457  } else {
458  return $data;
459  }
460  }
461 
470  protected function _getPatternReplacement($data, $contentType, $entityType = '')
471  {
472  if (!array_key_exists($contentType, $this->_replacePatterns)) {
473  return null;
474  }
475 
476  $replacements = [];
477  $pattern = $this->_replacePatterns[$contentType];
478  preg_match_all($pattern, $data, $matches, PREG_PATTERN_ORDER);
479  if (isset($matches['alias'])) {
480  $matches = array_unique($matches['alias']);
481  foreach ($matches as $classAlias) {
482  $className = $this->_getCorrespondingClassName($classAlias, $entityType);
483  if ($className) {
484  $replacements[$classAlias] = $className;
485  }
486  }
487  }
488 
489  foreach ($replacements as $classAlias => $className) {
490  $data = str_replace($classAlias, $className, $data);
491  }
492 
493  return $data;
494  }
495 
504  protected function _getClassName($module, $type, $name = null)
505  {
506  $className = implode('\\', array_map('ucfirst', explode('_', $module . '_' . $type . '_' . $name)));
507 
508  if (class_exists($className)) {
509  return $className;
510  }
511 
512  return '';
513  }
514 
521  protected function _isFactoryName($factoryName)
522  {
523  return false !== strpos($factoryName, '/') || preg_match('/^[a-z\d]+(_[A-Za-z\d]+)?$/', $factoryName);
524  }
525 
532  protected function _getModuleName($factoryName)
533  {
534  if (false !== strpos($factoryName, '/')) {
535  list($module, $name) = explode('/', $factoryName);
536  } else {
537  $module = $factoryName;
538  $name = false;
539  }
540  $compositeModuleName = $this->_getCompositeModuleName($module);
541  if (null !== $compositeModuleName) {
542  $module = $compositeModuleName;
543  } elseif (false === strpos($module, '_')) {
544  $module = "Magento_{$module}";
545  }
546  return [$module, $name];
547  }
548 
555  protected function _getCompositeModuleName($moduleAlias)
556  {
557  if (array_key_exists($moduleAlias, $this->_compositeModules)) {
558  return $this->_compositeModules[$moduleAlias];
559  }
560  return null;
561  }
562 
570  protected function _getAliasFromMap($alias, $entityType = '')
571  {
572  if ($map = $this->_getAliasesMap()) {
573  if (!empty($entityType) && isset($map[$entityType]) && !empty($map[$entityType][$alias])) {
574  return $map[$entityType][$alias];
575  } else {
576  $className = '';
577  foreach ($this->_entityTypes as $entityType) {
578  if (empty($className)) {
579  if (isset($map[$entityType]) && !empty($map[$entityType][$alias])) {
581  }
582  } else {
583  return '';
584  }
585  }
586  return $className;
587  }
588  }
589 
590  return '';
591  }
592 
601  protected function _pushToMap($entityType, $alias, $className)
602  {
603  // Load map from file if it wasn't loaded
604  $this->_getAliasesMap();
605 
606  if (!isset($this->_aliasesMap[$entityType])) {
607  $this->_aliasesMap[$entityType] = [];
608  }
609 
610  if (!isset($this->_aliasesMap[$entityType][$alias])) {
611  $this->_aliasesMap[$entityType][$alias] = $className;
612  }
613  }
614 
620  protected function _getAliasesMap()
621  {
622  if (null === $this->_aliasesMap) {
623  $this->_aliasesMap = [];
624 
625  $map = $this->_loadMap($this->_pathToMapFile);
626 
627  if (!empty($map)) {
628  $this->_aliasesMap = $this->_jsonDecode($map);
629  }
630  }
631 
632  return $this->_aliasesMap;
633  }
634 
641  protected function _loadMap($pathToMapFile)
642  {
643  if ($this->_directory->isFile($pathToMapFile)) {
644  return $this->_directory->readFile($pathToMapFile);
645  }
646 
647  return '';
648  }
649 
656  {
657  $matches = $this->_parseSerializedString($data);
658  if (isset($matches['alias']) && count($matches['alias']) > 0) {
659  foreach ($matches['alias'] as $key => $alias) {
661 
662  if (!empty($className)) {
663  $replaceString = sprintf(self::SERIALIZED_REPLACE_PATTERN, strlen($className), $className);
664  $data = str_replace($matches['string'][$key], $replaceString, $data);
665  }
666  }
667  }
668 
669  return $data;
670  }
671 
678  protected function _parseSerializedString($string)
679  {
680  if ($string && preg_match_all($this->_migrationData->getSerializedFindPattern(), $string, $matches)) {
681  unset($matches[0], $matches[1], $matches[2]);
682  return $matches;
683  } else {
684  return [];
685  }
686  }
687 
693  public function getCompositeModules()
694  {
696  }
697 
710  protected function _jsonDecode($encodedValue, $objectDecodeType = 1)
711  {
712  return $this->jsonDecode($encodedValue);
713  }
714 
723  private function jsonDecode($encodedValue)
724  {
725  return $this->serializer->unserialize($encodedValue);
726  }
727 }
_getAliasFromMap($alias, $entityType='')
Definition: Migration.php:570
_getReplacement($data, $contentType, $entityType='')
Definition: Migration.php:377
_getCorrespondingClassName($alias, $entityType='')
Definition: Migration.php:404
$tableName
Definition: trigger.php:13
_updateRowsData($tableName, $fieldName, array $fieldReplacements)
Definition: Migration.php:313
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
_getPatternReplacement($data, $contentType, $entityType='')
Definition: Migration.php:470
$pattern
Definition: website.php:22
_getClassName($module, $type, $name=null)
Definition: Migration.php:504
appendClassAliasReplace( $tableName, $fieldName, $entityType='', $fieldContentType=self::FIELD_CONTENT_TYPE_PLAIN, array $primaryKeyFields=[], $additionalWhere='')
Definition: Migration.php:178
_updateClassAliasesInTable($tableName, array $tableRules)
Definition: Migration.php:219
$replacement
Definition: website.php:23
_applyFieldRule($tableName, $fieldName, array $fieldRule, $currentPage=0)
Definition: Migration.php:267
$type
Definition: item.phtml:13
$value
Definition: gender.phtml:16
$page
Definition: pages.php:8
_jsonDecode($encodedValue, $objectDecodeType=1)
Definition: Migration.php:710
$setup
Definition: trigger.php:12
_getModelReplacement($data, $entityType='')
Definition: Migration.php:444
__construct(ModuleDataSetupInterface $setup, Filesystem $filesystem, MigrationData $migrationData, $confPathToMapFile, $compositeModules=[], \Magento\Framework\Serialize\Serializer\Json $serializer=null)
Definition: Migration.php:146
_getTableData( $tableName, $fieldName, array $fieldsToSelect, $additionalWhere='', $currPage=0)
Definition: Migration.php:342
if(!trim($html)) $alias
Definition: details.phtml:20
$connection
Definition: bulk.php:13
$filesystem
_pushToMap($entityType, $alias, $className)
Definition: Migration.php:601
_getAliasInSerializedStringReplacement($data, $entityType='')
Definition: Migration.php:655
_getRowsCount($tableName, $fieldName, $additionalWhere='')
Definition: Migration.php:240
if($currentSelectedMethod==$_code) $className
Definition: form.phtml:31
if(!isset($_GET['name'])) $name
Definition: log.php:14