diff --git a/mapping-experiment.php b/mapping-experiment.php new file mode 100644 index 000000000..c3ca56eb6 --- /dev/null +++ b/mapping-experiment.php @@ -0,0 +1,170 @@ + + */ + private array $pendingTasks = []; + + /** + * Important: this method returns a reference to a string which is also internally stored. + * It must be called like this: + * + * $data['someId'] = &$mappingService->getMapping('sourceId'); + * + * The use of '&' is very important, otherwise it will only copy the placeholder string. + * More info on this can be found in the PHP docs: + * https://www.php.net/manual/en/language.references.return.php + */ + public function &getMapping(string $sourceId): string + { + // previously we would fetch the mapping from the DB here, + // but reaching out to the DB every time is expensive + + // so instead we just return a placeholder string + // and update it later, when we know all mappings that are needed + + // and then use the string reference to update the placeholders + + $pointer = self::PLACEHOLDER; + + $task = new MappingTask($pointer, $sourceId); + $this->pendingTasks[] = $task; + + return $pointer; + } + + public function resolvePendingMappings(): void + { + // in here we can fetch all requested mappings from the DB + // in a single query and update all corresponding strings + foreach ($this->pendingTasks as $task) { + $task->reference = 'changed-' . $task->sourceId; + unset($task->reference); + } + } +} + +// a stripped-down example of a converter +function convertData(MappingService $mappingService): array +{ + $data['name'] = 'John Doe'; + $data['manufacturerId'] = &$mappingService->getMapping('manufacturer01'); + $data['price'] = []; + for ($i = 0; $i < 3; ++$i) { + $data['price'][] = convertCurrency($i, $mappingService); + } + + return $data; +} + +// a stripped-down example of internal logic in a converter +function convertCurrency(int $i, MappingService $mappingService): array +{ + $price = [ + 'id' => $i, + // unfortunately, this does not work, but there is an easy workaround below + // 'currencyId' => &$mappingService->getMapping('currency0' . $i), + ]; + + // this works fine + $price['currencyId'] = &$mappingService->getMapping('currency0' . $i); + + return $price; +} + +// === Main logic below === + +$mappingService = new MappingService(); +$convertedData = convertData($mappingService); +echo '============== Initial data after converter run ==============' . \PHP_EOL; +var_dump($convertedData); + +echo '============== data after mapping tasks got resolved ==============' . \PHP_EOL; +$mappingService->resolvePendingMappings(); +var_dump($convertedData); + +// === Output looks like this === +/* +============== Initial data after converter run ============== +array(3) { + ["name"]=> + string(8) "John Doe" + ["manufacturerId"]=> + &string(24) "placeholder-mapping-uuid" + ["price"]=> + array(3) { + [0]=> + array(2) { + ["id"]=> + int(0) + ["currencyId"]=> + &string(24) "placeholder-mapping-uuid" + } + [1]=> + array(2) { + ["id"]=> + int(1) + ["currencyId"]=> + &string(24) "placeholder-mapping-uuid" + } + [2]=> + array(2) { + ["id"]=> + int(2) + ["currencyId"]=> + &string(24) "placeholder-mapping-uuid" + } + } +} +============== data after mapping tasks got resolved ============== +array(3) { + ["name"]=> + string(8) "John Doe" + ["manufacturerId"]=> + string(22) "changed-manufacturer01" + ["price"]=> + array(3) { + [0]=> + array(2) { + ["id"]=> + int(0) + ["currencyId"]=> + string(18) "changed-currency00" + } + [1]=> + array(2) { + ["id"]=> + int(1) + ["currencyId"]=> + string(18) "changed-currency01" + } + [2]=> + array(2) { + ["id"]=> + int(2) + ["currencyId"]=> + string(18) "changed-currency02" + } + } +} + */ diff --git a/src/DependencyInjection/migration.xml b/src/DependencyInjection/migration.xml index a4235fa4f..9d4310b56 100644 --- a/src/DependencyInjection/migration.xml +++ b/src/DependencyInjection/migration.xml @@ -48,6 +48,13 @@ + + + + + + + @@ -226,6 +233,7 @@ + diff --git a/src/DependencyInjection/shopware.xml b/src/DependencyInjection/shopware.xml index bc5201298..aea5462de 100644 --- a/src/DependencyInjection/shopware.xml +++ b/src/DependencyInjection/shopware.xml @@ -115,6 +115,7 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SwagMigrationAssistant\Migration\Mapping; + +/** + * A promise that holds a reference to a string and the data for looking up a mapping. + * It makes it possible to update the referenced string at a later point and fulfill the promise to + * replace it with an actual UUID. + * + * If you are familiar with the JS world, this is a bit similar to a JS Promise, but + * there is no automatic executor in the background and these need to be manually fulfilled. + * + * @see MappingServiceV2 + * + * @internal + */ +#[Package('fundamentals@after-sales')] +class MappingPromise +{ + public function __construct( + /** + * points to the placeholder string that needs to be replaced with an actual UUID + */ + public string &$reference, + /** + * entity used for mapping lookup + */ + public string $entity, + /** + * source id used for mapping lookup + */ + public string $sourceId, + /** + * if true, the mapping will be created in DB if it does not exist + */ + public bool $shouldCreate = false, + /** + * if creating, use this Uuid to map to + */ + public ?string $createWith = null, + ) { + } + + public function resolve(string $uuid): void + { + $this->reference = $uuid; + unset($this->reference); + } +} diff --git a/src/Migration/Mapping/MappingService.php b/src/Migration/Mapping/MappingService.php index 54c8f05ab..36b8a2da8 100644 --- a/src/Migration/Mapping/MappingService.php +++ b/src/Migration/Mapping/MappingService.php @@ -114,6 +114,10 @@ public function getMapping( return $this->mappings[$cacheKey]; } + // simulate network latency + // todo: remove me + // \usleep(1000); // 1ms + $sql = 'SELECT id, connection_id AS connectionId, entity, diff --git a/src/Migration/Mapping/MappingServiceV2.php b/src/Migration/Mapping/MappingServiceV2.php new file mode 100644 index 000000000..2a99eca30 --- /dev/null +++ b/src/Migration/Mapping/MappingServiceV2.php @@ -0,0 +1,320 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SwagMigrationAssistant\Migration\Mapping; + +use Doctrine\DBAL\Connection; +use Psr\Log\LoggerInterface; +use Shopware\Core\Defaults; +use Shopware\Core\Framework\Uuid\Uuid; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @internal + */ +#[Package('fundamentals@after-sales')] +class MappingServiceV2 implements ResetInterface +{ + public const PLACEHOLDER = 'uuid-mapping-promise'; + + /** + * indexed by entityName + oldIdentifier + * the value is always a list with at least one promise + * + * @var array> + */ + private array $unfulfilledPromises = []; + + public function __construct( + protected readonly Connection $connection, + protected readonly LoggerInterface $logger, + ) { + } + + /** + * Lookup of a mapping with optional creation parameters if it doesn't exist yet. + * + * Important: this method returns a reference to a string which is also internally stored. + * It must be called like this: + * + * $data['newId'] = &$mappingService->getMapping('entity', 'oldId'); + * + * The use of '&' is very important, otherwise it will only copy the placeholder string. + * More info on this can be found in the PHP docs: + * https://www.php.net/manual/en/language.references.return.php + * + * @param bool $shouldCreate if the mapping should be created if it doesn't exist yet + * @param string|null $createWith if creating, use this Uuid to map to. All the same lookups will resolve to this + * + * @return string placeholder string which will be resolved later by calling @see MappingServiceV2->resolvePromises() + */ + public function &getMapping( + string $entityName, + string $oldIdentifier, + bool $shouldCreate = false, + ?string $createWith = null, + ): string { + // todo: figure out a nice dev experience for debugging + // todo: this is already a good start? + $trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 1); + $caller = $trace[0] ?? []; + $callerString = ($caller['file'] ?? '') . '::' . ($caller['line'] ?? ''); + + $ref = self::PLACEHOLDER . '(\'' . $entityName . '\', \'' . $oldIdentifier . '\') +++ ' . $callerString; + + $promise = new MappingPromise($ref, $entityName, $oldIdentifier, $shouldCreate, $createWith); + + $key = $entityName . $oldIdentifier; + if (!isset($this->unfulfilledPromises[$key])) { + $this->unfulfilledPromises[$key] = []; + } + $this->unfulfilledPromises[$key][] = $promise; + + return $ref; + } + + public function resolvePromises( + string $connectionId, + ): void { + if ($this->unfulfilledPromises === []) { + return; + } + + $mappingLookups = array_map( + fn ($mappingPromises) => [ + 'entity' => $mappingPromises[0]->entity, + 'oldIdentifier' => $mappingPromises[0]->sourceId, + ], + $this->unfulfilledPromises, + ); + $dbMappings = $this->fetchDbMappings($connectionId, $mappingLookups); + + foreach ($dbMappings as $dbMapping) { + $key = $dbMapping->getEntity() . $dbMapping->getOldIdentifier(); + $promises = $this->unfulfilledPromises[$key]; + foreach ($promises as $promise) { + $promise->resolve($dbMapping->getEntityId()); + } + unset($this->unfulfilledPromises[$key]); + } + + // the remaining unfulfilled promises don't have a DB mapping yet + $createDbMappings = []; + foreach ($this->unfulfilledPromises as $promises) { + // search if this particular lookup is allowed to create a mapping + // and if exactly one createWith value was provided + $shouldCreate = false; + $createWith = null; + foreach ($promises as $promise) { + if ($promise->shouldCreate) { + $shouldCreate = true; + } + if ($promise->createWith) { + if ($createWith) { + // todo: proper error handling + throw new \RuntimeException('resolving mapping promise failed with multiple createWith values for ' . $promises[0]->sourceId . ' for ' . $promises[0]->entity); + } + + $createWith = $promise->createWith; + } + } + + if (!$shouldCreate) { + // todo: proper error handling + throw new \RuntimeException('Could not resolve mapping promise ' . $promises[0]->sourceId . ' for ' . $promises[0]->entity); + } + + // it's fine to create the corresponding mapping and resolve all promises with its value + $newEntityId = $createWith ?? Uuid::randomHex(); + + $dbMapping = new SwagMigrationMappingEntity(); + $dbMapping->setId(Uuid::randomHex()); + $dbMapping->setConnectionId($connectionId); + $dbMapping->setEntity($promises[0]->entity); + $dbMapping->setOldIdentifier($promises[0]->sourceId); + $dbMapping->setEntityId($newEntityId); + $dbMapping->setCreatedAt(new \DateTime()); + + $createDbMappings[] = $dbMapping; + + // resolve promises + // todo: should this only execute after successful DB insert? + foreach ($promises as $promise) { + $promise->resolve($newEntityId); + } + } + + unset($this->unfulfilledPromises); + $this->unfulfilledPromises = []; + + $this->bulkCreateDbMappings($createDbMappings); + } + + public function reset(): void + { + if ($this->unfulfilledPromises !== []) { + $this->logger->error('Resetting MappingServiceV2 without resolving all promises'); + } + + unset($this->unfulfilledPromises); + $this->unfulfilledPromises = []; + } + + // todo: move SQL methods below into own class and try to clean them up further + /** + * @param list $lookups + * + * @return list + */ + private function fetchDbMappings(string $connectionId, array $lookups): array + { + if ($lookups === []) { + return []; + } + + $placeholders = []; + $params = []; + + foreach ($lookups as $pair) { + $placeholders[] = '(?, ?)'; + $params[] = $pair['entity']; + $params[] = $pair['oldIdentifier']; + } + + $sql = \sprintf( + 'SELECT id, + connection_id AS connectionId, + entity, + old_identifier AS oldIdentifier, + entity_id AS entityId, + entity_value AS entityValue, + checksum, + additional_data AS additionalData + FROM swag_migration_mapping + WHERE connection_id = :connectionId AND (entity, old_identifier) IN (%s)', + implode(', ', $placeholders) + ); + + $mappings = $this->connection->fetchAllAssociative( + $sql, + [ + 'connectionId' => Uuid::fromHexToBytes($connectionId), + ...$params, + ], + [ + 'connectionId' => 'binary', + ] + ); + + return array_map( + function (array $mapping): SwagMigrationMappingEntity { + $mapping['id'] = Uuid::fromBytesToHex($mapping['id']); + $mapping['connectionId'] = Uuid::fromBytesToHex($mapping['connectionId']); + $mapping['entityId'] = isset($mapping['entityId']) ? Uuid::fromBytesToHex($mapping['entityId']) : null; + + $entity = new SwagMigrationMappingEntity(); + $entity->assign($mapping); + + return $entity; + }, + $mappings, + ); + } + + /** + * @param list $mappings + */ + private function bulkCreateDbMappings(array $mappings): void + { + if ($mappings === []) { + return; + } + + try { + $isFirstInsert = true; + $insertSql = 'INSERT INTO swag_migration_mapping (id, connection_id, entity, old_identifier, entity_id, entity_value, checksum, additional_data, created_at) VALUES '; + $insertParams = []; + $updateSql = ' ON DUPLICATE KEY + UPDATE entity = VALUES(entity), + old_identifier = VALUES(old_identifier), + entity_id = VALUES(entity_id), + entity_value = VALUES(entity_value), + checksum = VALUES(checksum), + additional_data = VALUES(additional_data), + updated_at = VALUES(created_at);'; + foreach ($mappings as $index => $writeMapping) { + if ($isFirstInsert) { + $isFirstInsert = false; + } else { + $insertSql .= ', '; + } + + $insertSql .= \sprintf('(:id%d, :connectionId%d, :entity%d, :oldIdentifier%d, :entityId%d, :entityValue%d, :checksum%d, :additionalData%d, :createdAt%d)', $index, $index, $index, $index, $index, $index, $index, $index, $index); + + $insertParams['id' . $index] = Uuid::fromHexToBytes($writeMapping->getId()); + $insertParams['connectionId' . $index] = Uuid::fromHexToBytes($writeMapping->getConnectionId()); + $insertParams['entity' . $index] = $writeMapping->getEntity(); + $insertParams['oldIdentifier' . $index] = $writeMapping->getOldIdentifier(); + $insertParams['entityId' . $index] = $writeMapping->getEntityId() === null ? null : Uuid::fromHexToBytes($writeMapping->getEntityId()); + $insertParams['entityValue' . $index] = $writeMapping->getEntityValue(); + $insertParams['checksum' . $index] = $writeMapping->getChecksum(); + $insertParams['additionalData' . $index] = \json_encode($writeMapping->getAdditionalData()); + $insertParams['createdAt' . $index] = $writeMapping->getCreatedAt()->format(Defaults::STORAGE_DATE_TIME_FORMAT); + } + + $this->connection->executeStatement($insertSql . $updateSql, $insertParams); + } catch (\Exception) { + $this->createDbMappingsIndividually($mappings); + } + } + + /** + * @param list $mappings + */ + private function createDbMappingsIndividually(array $mappings): void + { + if ($mappings === []) { + return; + } + + foreach ($mappings as $writeMapping) { + try { + $insertSql = 'INSERT INTO swag_migration_mapping (id, connection_id, entity, old_identifier, entity_id, entity_value, checksum, additional_data, created_at) + VALUES (:id, :connectionId, :entity, :oldIdentifier, :entityId, :entityValue, :checksum, :additionalData, :createdAt) + ON DUPLICATE KEY + UPDATE entity = VALUES(entity), + old_identifier = VALUES(old_identifier), + entity_id = VALUES(entity_id), + entity_value = VALUES(entity_value), + checksum = VALUES(checksum), + additional_data = VALUES(additional_data), + updated_at = VALUES(created_at);'; + + $insertParams = []; + $insertParams['id'] = Uuid::fromHexToBytes($writeMapping->getId()); + $insertParams['connectionId'] = Uuid::fromHexToBytes($writeMapping->getConnectionId()); + $insertParams['entity'] = $writeMapping->getEntity(); + $insertParams['oldIdentifier'] = $writeMapping->getOldIdentifier(); + $insertParams['entityId'] = $writeMapping->getEntityId() === null ? null : Uuid::fromHexToBytes($writeMapping->getEntityId()); + $insertParams['entityValue'] = $writeMapping->getEntityValue(); + $insertParams['checksum'] = $writeMapping->getChecksum(); + $insertParams['additionalData'] = \json_encode($writeMapping->getAdditionalData()); + $insertParams['createdAt'] = $writeMapping->getCreatedAt()->format(Defaults::STORAGE_DATE_TIME_FORMAT); + + $this->connection->executeStatement($insertSql, $insertParams); + } catch (\Exception $e) { + $this->logger->error( + 'SwagMigrationAssistant: Error while writing migration mapping', + [ + 'error' => $e->getMessage(), + 'mapping' => $writeMapping, + ] + ); + } + } + } +} diff --git a/src/Migration/Mapping/SwagMigrationMappingEntity.php b/src/Migration/Mapping/SwagMigrationMappingEntity.php index 284487165..20a06a0d3 100644 --- a/src/Migration/Mapping/SwagMigrationMappingEntity.php +++ b/src/Migration/Mapping/SwagMigrationMappingEntity.php @@ -21,20 +21,20 @@ class SwagMigrationMappingEntity extends Entity protected ?SwagMigrationConnectionEntity $connection = null; - protected ?string $entity; + protected ?string $entity = null; - protected ?string $oldIdentifier; + protected ?string $oldIdentifier = null; - protected ?string $entityId; + protected ?string $entityId = null; - protected ?string $entityValue; + protected ?string $entityValue = null; - protected ?string $checksum; + protected ?string $checksum = null; /** * @var array|null */ - protected ?array $additionalData; + protected ?array $additionalData = null; public function getConnectionId(): string { diff --git a/src/Migration/Media/MediaFileService.php b/src/Migration/Media/MediaFileService.php index a3bce2867..f9ec762c2 100644 --- a/src/Migration/Media/MediaFileService.php +++ b/src/Migration/Media/MediaFileService.php @@ -75,6 +75,7 @@ public function writeMediaFile(Context $context): void public function saveMediaFile(array $mediaFile): void { + // todo: this is likely broken with MappingServiceV2 and needs to be checked, maybe refactored $mediaId = $mediaFile['mediaId']; if (isset($this->uuids[$mediaId])) { return; diff --git a/src/Migration/MessageQueue/Handler/Processor/FetchingProcessor.php b/src/Migration/MessageQueue/Handler/Processor/FetchingProcessor.php index 2dfaa742b..d255bf9d9 100644 --- a/src/Migration/MessageQueue/Handler/Processor/FetchingProcessor.php +++ b/src/Migration/MessageQueue/Handler/Processor/FetchingProcessor.php @@ -61,6 +61,20 @@ public function process( ): void { $runId = $migrationContext->getRunUuid(); $totalCountOfCurrentEntity = $progress->getDataSets()->getTotalByEntityName($progress->getCurrentEntity()); + + // todo: remove benchmarking code + if ($progress->getCurrentEntity() === 'product' && $progress->getCurrentEntityProgress() === 0) { + $blackfire = new \Blackfire\Client(); + $config = new \Blackfire\Profile\Configuration(); + $config->setTitle('Fetching ' . $progress->getCurrentEntity() . ' ' . $progress->getCurrentEntityProgress() . ' / ' . $totalCountOfCurrentEntity . ' limit ' . $migrationContext->getLimit()); + $config->setMetadata('entity', $progress->getCurrentEntity()); + $config->setMetadata('progress', (string) $progress->getCurrentEntityProgress()); + $config->setMetadata('total', (string) $totalCountOfCurrentEntity); + $config->setMetadata('limit', (string) $migrationContext->getLimit()); + $probe = $blackfire->createProbe($config); + // code being profiled... + } + $data = $this->migrationDataFetcher->fetchData($migrationContext, $context); if ($progress->getCurrentEntityProgress() >= $totalCountOfCurrentEntity) { @@ -81,6 +95,13 @@ public function process( $progress->setProgress($progress->getProgress() + \count($data)); $this->updateProgress($runId, $progress, $context); + + // todo: remove benchmarking code + if ($progress->getCurrentEntity() === 'product' && $progress->getCurrentEntityProgress() === 0) { + // end profiling + $profile = $blackfire->endProbe($probe); + } + $this->bus->dispatch(new MigrationProcessMessage($context, $migrationContext->getRunUuid())); } } diff --git a/src/Migration/Service/MigrationDataConverter.php b/src/Migration/Service/MigrationDataConverter.php index 92a56366e..fc9f13015 100644 --- a/src/Migration/Service/MigrationDataConverter.php +++ b/src/Migration/Service/MigrationDataConverter.php @@ -23,6 +23,7 @@ use SwagMigrationAssistant\Migration\Logging\LoggingServiceInterface; use SwagMigrationAssistant\Migration\Mapping\MappingDeltaResult; use SwagMigrationAssistant\Migration\Mapping\MappingServiceInterface; +use SwagMigrationAssistant\Migration\Mapping\MappingServiceV2; use SwagMigrationAssistant\Migration\Media\MediaFileServiceInterface; use SwagMigrationAssistant\Migration\MigrationContextInterface; use SwagMigrationAssistant\Migration\Validation\MigrationEntityValidationService; @@ -38,6 +39,7 @@ public function __construct( private readonly EntityDefinition $dataDefinition, private readonly MappingServiceInterface $mappingService, private readonly MigrationEntityValidationService $validationService, + private readonly MappingServiceV2 $mappingServiceV2, ) { } @@ -91,6 +93,7 @@ private function convertData( ): array { $runUuid = $migrationContext->getRunUuid(); + $convertData = []; $createData = []; foreach ($data as $item) { try { @@ -106,8 +109,43 @@ private function convertData( continue; } - $convertFailureFlag = empty($convertStruct->getConverted()); + $convertData[] = [ + 'convertStruct' => $convertStruct, + 'item' => $item, + ]; + } catch (\Throwable $exception) { + $this->loggingService->log( + MigrationLogBuilder::fromMigrationContext($migrationContext) + ->withExceptionMessage($exception->getMessage()) + ->withExceptionTrace($exception->getTrace()) + ->withEntityName($dataSet::getEntity()) + ->withSourceData($item) + ->build(RunExceptionLog::class) + ); + $createData[] = [ + 'entity' => $dataSet::getEntity(), + 'runId' => $runUuid, + 'raw' => $item, + 'converted' => null, + 'unmapped' => $item, + 'mappingUuid' => null, + 'convertFailure' => true, + ]; + } + } + + // todo: this can throw as well + $this->mappingServiceV2->resolvePromises($migrationContext->getConnection()->getId()); + + // todo: validation needs to be called after the whole batch was converted + mappings resolved + // todo: should be refactored to work with batches and be outsourced like MigrationDataFetcher + MigrationDataConverter + // todo: for now this is a temporary ugly workaround + foreach ($convertData as $convertItem) { + $convertStruct = $convertItem['convertStruct']; + $item = $convertItem['item']; + + try { $this->validationService->validate( $migrationContext, $context, @@ -116,6 +154,8 @@ private function convertData( $item ); + $convertFailureFlag = empty($convertStruct->getConverted()); + $createData[] = [ 'entity' => $dataSet::getEntity(), 'runId' => $runUuid, @@ -144,8 +184,6 @@ private function convertData( 'mappingUuid' => null, 'convertFailure' => true, ]; - - continue; } } diff --git a/src/Profile/Shopware/Converter/ProductConverter.php b/src/Profile/Shopware/Converter/ProductConverter.php index e9d534751..c5effb900 100644 --- a/src/Profile/Shopware/Converter/ProductConverter.php +++ b/src/Profile/Shopware/Converter/ProductConverter.php @@ -32,6 +32,7 @@ use SwagMigrationAssistant\Migration\Mapping\Lookup\MediaDefaultFolderLookup; use SwagMigrationAssistant\Migration\Mapping\Lookup\TaxLookup; use SwagMigrationAssistant\Migration\Mapping\MappingServiceInterface; +use SwagMigrationAssistant\Migration\Mapping\MappingServiceV2; use SwagMigrationAssistant\Migration\Media\MediaFileServiceInterface; use SwagMigrationAssistant\Migration\MigrationContextInterface; use SwagMigrationAssistant\Migration\Validation\Log\MigrationValidationRequiredFieldMissingLog; @@ -80,6 +81,7 @@ public function __construct( protected readonly MediaDefaultFolderLookup $mediaFolderLookup, protected readonly LanguageLookup $languageLookup, protected readonly DeliveryTimeLookup $deliveryTimeLookup, + protected readonly MappingServiceV2 $mappingServiceV2, ) { parent::__construct($mappingService, $loggingService); } @@ -187,11 +189,8 @@ public function convert( if (empty($returnData)) { $returnData = null; } - $this->updateMainMapping($migrationContext, $context); - $mainMapping = $this->mainMapping['id'] ?? null; - - return new ConvertStruct($converted, $returnData, $mainMapping); + return new ConvertStruct($converted, $returnData, null); } /** @@ -199,17 +198,14 @@ public function convert( */ protected function convertMainProduct(array $data): ConvertStruct { - $containerMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $containerUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_CONTAINER, $data['id'], - $this->context + true, ); - $containerUuid = $containerMapping['entityId']; $converted = []; - $converted['id'] = $containerUuid; - $this->mappingIds[] = $containerMapping['id']; + $converted['id'] = &$containerUuid; unset($data['detail']['articleID']); $converted = $this->getProductData($data, $converted); @@ -218,37 +214,27 @@ protected function convertMainProduct(array $data): ConvertStruct $converted['productNumber'] .= 'M'; // Remove options from product container as in core unset($converted['options']); - $this->mainMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, - DefaultEntities::PRODUCT, - $this->oldProductId, - $this->context, - $this->checksum - ); - $converted['children'][0]['id'] = $this->mainMapping['entityId']; + $productUuid = &$this->mappingServiceV2->getMapping(DefaultEntities::PRODUCT, $this->oldProductId, true); + $converted['children'][0]['id'] = &$productUuid; if (isset($converted['children'][0]['media'])) { if (isset($converted['children'][0]['cover'])) { $coverMediaUuid = $converted['children'][0]['cover']['media']['id']; } foreach ($converted['children'][0]['media'] as &$media) { - $productMediaRelationMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $media['productId'] = &$productUuid; + $media['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_MEDIA, $media['id'], - $this->context + true, ); - $productMediaRelationUuid = $productMediaRelationMapping['entityId']; - $this->mappingIds[] = $productMediaRelationMapping['id']; - $media['productId'] = $this->mainMapping['entityId']; - $media['id'] = $productMediaRelationUuid; if (isset($coverMediaUuid) && $media['media']['id'] === $coverMediaUuid) { $converted['children'][0]['cover'] = $media; } } } - $converted['children'][0]['parentId'] = $containerUuid; + $converted['children'][0]['parentId'] = &$containerUuid; unset($data['detail']['id'], $converted['children'][0]['translations'], $converted['children'][0]['customFields']); if (isset($data['categories'])) { @@ -271,7 +257,7 @@ protected function convertMainProduct(array $data): ConvertStruct } $this->updateMainMapping($this->migrationContext, $this->context); - return new ConvertStruct($converted, $returnData, $this->mainMapping['id'] ?? null); + return new ConvertStruct($converted, $returnData, null); } /** @@ -281,29 +267,16 @@ protected function convertMainProduct(array $data): ConvertStruct */ protected function convertVariantProduct(array $data): ConvertStruct { - $parentMapping = $this->mappingService->getMapping( - $this->connectionId, - DefaultEntities::PRODUCT_CONTAINER, - $data['detail']['articleID'], - $this->context - ); - - if ($parentMapping === null) { - throw MigrationException::parentEntityForChildNotFound(DefaultEntities::PRODUCT, $this->oldProductId); - } - - $this->mainMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $converted = []; + $converted['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT, $this->oldProductId, - $this->context, - $this->checksum + true + ); + $converted['parentId'] = &$this->mappingServiceV2->getMapping( + DefaultEntities::PRODUCT_CONTAINER, + $data['detail']['articleID'] ); - - $converted = []; - $converted['id'] = $this->mainMapping['entityId']; - $converted['parentId'] = $parentMapping['entityId']; - $this->mappingIds[] = $parentMapping['id']; $converted = $this->getProductData($data, $converted); unset($data['detail']['id'], $data['detail']['articleID'], $data['categories']); @@ -315,11 +288,8 @@ protected function convertVariantProduct(array $data): ConvertStruct if (empty($returnData)) { $returnData = null; } - $this->updateMainMapping($this->migrationContext, $this->context); - $mainMapping = $this->mainMapping['id'] ?? null; - - return new ConvertStruct($converted, $returnData, $mainMapping); + return new ConvertStruct($converted, $returnData, null); } /** @@ -329,27 +299,23 @@ protected function convertVariantProduct(array $data): ConvertStruct */ private function getUuidForProduct(array &$data): array { - $this->mainMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $converted = []; + $newUuid = Uuid::randomHex(); + $converted['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT, $this->oldProductId, - $this->context, - $this->checksum + true, + $newUuid, ); - $converted = []; - $converted['id'] = $this->mainMapping['entityId']; - - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + // create another mapping that resolves to the same UUID as the mapping above + // but uses a different lookup pair + $this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_MAIN, $data['detail']['articleID'], - $this->context, - null, - null, - $converted['id'] + true, + $newUuid ); - $this->mappingIds[] = $mapping['id']; return $converted; } @@ -524,10 +490,6 @@ private function getProductData(array &$data, array $converted): array */ private function setPurchasePrices(array &$data, array &$converted): void { - if ($this->currencyUuid === null) { - return; - } - $purchasePrice = 0.0; $purchasePriceGross = 0.0; if (isset($data['detail']['purchaseprice'])) { @@ -537,6 +499,8 @@ private function setPurchasePrices(array &$data, array &$converted): void unset($data['detail']['purchaseprice']); $price = []; + // todo: validate this is fine + /* if ($this->currencyUuid !== Defaults::CURRENCY) { $price[] = [ 'currencyId' => Defaults::CURRENCY, @@ -545,9 +509,10 @@ private function setPurchasePrices(array &$data, array &$converted): void 'linked' => true, ]; } + */ $price[] = [ - 'currencyId' => $this->currencyUuid, + 'currencyId' => &$this->currencyUuid, 'gross' => $purchasePriceGross, 'net' => $purchasePrice, 'linked' => true, @@ -596,19 +561,6 @@ private function getDeliveryTime(string $shippingTime): ?array } } - $mapping = $this->mappingService->getMapping( - $this->connectionId, - DefaultEntities::DELIVERY_TIME, - $shippingTime, - $this->context - ); - - if ($mapping !== null) { - $convertedDeliveryTime['id'] = $mapping['entityId']; - - return $convertedDeliveryTime; - } - $convertedDeliveryTime['id'] = $this->deliveryTimeLookup->get( $convertedDeliveryTime['min'], $convertedDeliveryTime['max'], @@ -617,18 +569,13 @@ private function getDeliveryTime(string $shippingTime): ?array ); if ($convertedDeliveryTime['id'] === null) { - $convertedDeliveryTime['id'] = Uuid::randomHex(); + $convertedDeliveryTime['id'] = &$this->mappingServiceV2->getMapping( + DefaultEntities::DELIVERY_TIME, + $shippingTime, + true, + ); } - $this->mappingService->createMapping( - $this->connectionId, - DefaultEntities::DELIVERY_TIME, - $shippingTime, - null, - null, - $convertedDeliveryTime['id'], - ); - return $convertedDeliveryTime; } @@ -662,24 +609,20 @@ private function applyOptions(array &$converted, array &$data): void } foreach ($data['configuratorOptions'] as $option) { - $optionMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $optionUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::PROPERTY_GROUP_OPTION, Hasher::hash(\mb_strtolower($option['name'] . '_' . $option['group']['name']), 'md5'), - $this->context + true, ); - $this->mappingIds[] = $optionMapping['id']; - $optionGroupMapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $optionGroupUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::PROPERTY_GROUP, Hasher::hash(\mb_strtolower($option['group']['name']), 'md5'), - $this->context + true, ); - $this->mappingIds[] = $optionGroupMapping['id']; $optionElement = [ - 'id' => $optionMapping['entityId'], + 'id' => &$optionUuid, 'group' => [ - 'id' => $optionGroupMapping['entityId'], + 'id' => &$optionGroupUuid, ], ]; @@ -707,15 +650,12 @@ private function applyOptions(array &$converted, array &$data): void */ private function getManufacturer(array $data): array { - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $manufacturer = []; + $manufacturer['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_MANUFACTURER, $data['id'], - $this->context + true, ); - $manufacturer = []; - $manufacturer['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $this->applyManufacturerTranslation($manufacturer, $data); $this->convertValue($manufacturer, 'link', $data, 'link'); @@ -750,19 +690,16 @@ private function applyManufacturerTranslation(array &$manufacturer, array $data) } $localeTranslation = []; - $localeTranslation['productManufacturerId'] = $manufacturer['id']; + $localeTranslation['productManufacturerId'] = &$manufacturer['id']; $this->convertValue($localeTranslation, 'name', $data, 'name'); $this->convertValue($localeTranslation, 'description', $data, 'description'); - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $localeTranslation['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_MANUFACTURER_TRANSLATION, $data['id'] . ':' . $this->locale, - $this->context + true, ); - $localeTranslation['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $languageUuid = $this->languageLookup->get($this->locale, $this->context); if ($languageUuid !== null) { @@ -781,21 +718,19 @@ private function getTax(array $taxData): array $taxRate = (float) $taxData['tax']; $taxUuid = $this->taxLookup->get($taxRate, $this->context); if (empty($taxUuid)) { - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $taxUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::TAX, $taxData['id'], - $this->context + true, ); - $taxUuid = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; } - return [ - 'id' => $taxUuid, - 'taxRate' => $taxRate, - 'name' => $taxData['description'], - ]; + $tax = []; + $tax['id'] = &$taxUuid; + $tax['taxRate'] = $taxRate; + $tax['name'] = $taxData['description']; + + return $tax; } /** @@ -806,14 +741,11 @@ private function getTax(array $taxData): array private function getUnit(array $data): array { $unit = []; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $unit['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::UNIT, $data['id'], - $this->context + true, ); - $unit['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $this->applyUnitTranslation($unit, $data); $this->convertValue($unit, 'shortCode', $data, 'unit'); @@ -843,14 +775,11 @@ private function applyUnitTranslation(array &$unit, array $data): void $this->convertValue($localeTranslation, 'shortCode', $data, 'unit'); $this->convertValue($localeTranslation, 'name', $data, 'description'); - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $localeTranslation['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::UNIT_TRANSLATION, $data['id'] . ':' . $this->locale, - $this->context + true, ); - $localeTranslation['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $languageUuid = $this->languageLookup->get($this->locale, $this->context); if ($languageUuid !== null) { @@ -870,28 +799,21 @@ private function getEsdFiles(array $esdFiles, string $oldVariantId, array $conve $mediaObjects = []; foreach ($esdFiles as $esdFile) { $newProductMedia = []; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $newProductMedia['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_DOWNLOAD, $oldVariantId . '_' . $esdFile['id'], - $this->context + true, ); - $newProductMedia['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $newProductMedia['productId'] = $converted['id']; + $newProductMedia['productId'] = &$converted['id']; /** @var array $newMedia */ $newMedia = []; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $newMedia['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::MEDIA, 'esd_' . $esdFile['id'], - $this->context + true, ); - $newMedia['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - if (empty($esdFile['name'])) { $this->loggingService->log( MigrationLogBuilder::fromMigrationContext($this->migrationContext) @@ -931,7 +853,7 @@ private function getEsdFiles(array $esdFiles, string $oldVariantId, array $conve 'uri' => $path . '/' . $esdFile['name'], 'fileName' => $esdFile['name'], 'fileSize' => 0, - 'mediaId' => $newMedia['id'], + 'mediaId' => &$newMedia['id'], ] ); @@ -999,26 +921,20 @@ private function getMedia(array $media, string $oldVariantId, array $converted): } $newProductMedia = []; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $newProductMedia['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_MEDIA, $oldVariantId . $mediaData['id'], - $this->context + true, ); - $newProductMedia['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $newProductMedia['productId'] = $converted['id']; + $newProductMedia['productId'] = &$converted['id']; $this->convertValue($newProductMedia, 'position', $mediaData, 'position', self::TYPE_INTEGER); $newMedia = []; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $newMedia['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::MEDIA, $mediaData['media']['id'], - $this->context + true, ); - $newMedia['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; if (empty($mediaData['media']['name'])) { $mediaData['media']['name'] = $newMedia['id']; @@ -1031,7 +947,7 @@ private function getMedia(array $media, string $oldVariantId, array $converted): 'uri' => $mediaData['media']['uri'] ?? $mediaData['media']['path'], 'fileName' => $mediaData['media']['name'], 'fileSize' => (int) $mediaData['media']['file_size'], - 'mediaId' => $newMedia['id'], + 'mediaId' => &$newMedia['id'], ] ); @@ -1039,16 +955,11 @@ private function getMedia(array $media, string $oldVariantId, array $converted): $this->convertValue($newMedia, 'title', $mediaData['media'], 'name'); $this->convertValue($newMedia, 'alt', $mediaData, 'description'); - $albumMapping = $this->mappingService->getMapping( - $this->connectionId, - DefaultEntities::MEDIA_FOLDER, - $mediaData['media']['albumID'], - $this->context - ); - - if ($albumMapping !== null) { - $newMedia['mediaFolderId'] = $albumMapping['entityId']; - $this->mappingIds[] = $albumMapping['id']; + if (!empty($mediaData['media']['albumID'])) { + $newMedia['mediaFolderId'] = &$this->mappingServiceV2->getMapping( + DefaultEntities::MEDIA_FOLDER, + $mediaData['media']['albumID'], + ); } $newProductMedia['media'] = $newMedia; @@ -1143,14 +1054,11 @@ private function applyMediaTranslation(array &$media, array $data): void $this->convertValue($localeTranslation, 'title', $data['media'], 'name'); $this->convertValue($localeTranslation, 'alt', $data, 'description'); - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $localeTranslation['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::MEDIA_TRANSLATION, $data['media']['id'] . ':' . $this->locale, - $this->context + true, ); - $localeTranslation['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $languageUuid = $this->languageLookup->get($this->locale, $this->context); if ($languageUuid !== null) { @@ -1166,15 +1074,12 @@ private function applyMediaTranslation(array &$media, array $data): void */ private function getManufacturerMedia(array $media): array { - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $manufacturerMedia = []; + $manufacturerMedia['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::MEDIA, $media['id'], - $this->context + true, ); - $manufacturerMedia = []; - $manufacturerMedia['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; if (empty($media['name'])) { $media['name'] = $manufacturerMedia['id']; @@ -1182,16 +1087,11 @@ private function getManufacturerMedia(array $media): array $this->applyMediaTranslation($manufacturerMedia, ['media' => $media]); - $albumMapping = $this->mappingService->getMapping( - $this->connectionId, - DefaultEntities::MEDIA_FOLDER, - $media['albumID'], - $this->context - ); - - if ($albumMapping !== null) { - $manufacturerMedia['mediaFolderId'] = $albumMapping['entityId']; - $this->mappingIds[] = $albumMapping['id']; + if (!empty($media['albumID'])) { + $manufacturerMedia['mediaFolderId'] = &$this->mappingServiceV2->getMapping( + DefaultEntities::MEDIA_FOLDER, + $media['albumID'], + ); } $this->mediaFileService->saveMediaFile( @@ -1201,7 +1101,7 @@ private function getManufacturerMedia(array $media): array 'uri' => $media['uri'] ?? $media['path'], 'fileName' => $media['name'], 'fileSize' => (int) $media['file_size'], - 'mediaId' => $manufacturerMedia['id'], + 'mediaId' => &$manufacturerMedia['id'], ] ); @@ -1219,26 +1119,20 @@ private function applyOptionTranslation(array &$option, array $data): void $localeOptionTranslation['languageId'] = $languageUuid; $localeGroupTranslation = $localeOptionTranslation; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $localeOptionTranslation['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PROPERTY_GROUP_OPTION_TRANSLATION, Hasher::hash(\mb_strtolower($data['name'] . '_' . $data['group']['name']), 'md5') . ':' . $this->locale, - $this->context + true, ); - $localeOptionTranslation['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $this->convertValue($localeOptionTranslation, 'name', $data, 'name'); $this->convertValue($localeOptionTranslation, 'position', $data, 'position', self::TYPE_INTEGER); - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $localeGroupTranslation['id'] = &$this->mappingServiceV2->getMapping( DefaultEntities::PROPERTY_GROUP_TRANSLATION, Hasher::hash(\mb_strtolower($data['group']['name']), 'md5') . ':' . $this->locale, - $this->context + true, ); - $localeGroupTranslation['id'] = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $this->convertValue($localeGroupTranslation, 'name', $data['group'], 'name'); $this->convertValue($localeGroupTranslation, 'description', $data['group'], 'description'); @@ -1259,20 +1153,15 @@ private function getPrice(array $priceData, float $taxRate): array $gross = \round((float) $priceData['price'] * (1 + $taxRate / 100), $this->context->getRounding()->getDecimals()); if (isset($priceData['currencyShortName'])) { - $currencyMapping = $this->mappingService->getMapping( - $this->connectionId, + $this->currencyUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::CURRENCY, $priceData['currencyShortName'], - $this->context ); } - if (!isset($currencyMapping)) { - return []; - } - $this->currencyUuid = $currencyMapping['entityId']; - $this->mappingIds[] = $currencyMapping['id']; $price = []; + // todo: validate that removing this is fine + /* if ($this->currencyUuid !== Defaults::CURRENCY) { $price[] = [ 'currencyId' => Defaults::CURRENCY, @@ -1281,9 +1170,10 @@ private function getPrice(array $priceData, float $taxRate): array 'linked' => true, ]; } + */ $price[] = [ - 'currencyId' => $this->currencyUuid, + 'currencyId' => &$this->currencyUuid, 'gross' => $gross, 'net' => (float) $priceData['price'], 'linked' => true, @@ -1293,7 +1183,7 @@ private function getPrice(array $priceData, float $taxRate): array if ($listPrice > 0) { $listPriceGross = \round((float) $priceData['pseudoprice'] * (1 + $taxRate / 100), $this->context->getRounding()->getDecimals()); $price[0]['listPrice'] = [ - 'currencyId' => $this->currencyUuid, + 'currencyId' => &$this->currencyUuid, 'gross' => $listPriceGross, 'net' => $listPrice, 'linked' => true, @@ -1317,63 +1207,40 @@ private function getPrices(array $priceData, array $converted): array continue; } - $customerGroupMapping = $this->mappingService->getMapping( - $this->connectionId, + $customerGroupUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::CUSTOMER_GROUP, $price['customergroup']['id'], - $this->context ); - if ($customerGroupMapping === null) { - continue; - } - $customerGroupUuid = $customerGroupMapping['entityId']; - $this->mappingIds[] = $customerGroupMapping['id']; - - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $productPriceRuleUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::RULE, 'customerGroupRule_productPriceRule_' . $price['id'] . '_' . $price['customergroup']['id'], - $this->context + true, ); - $productPriceRuleUuid = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $priceRuleUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::RULE, 'customerGroupRule_' . $price['customergroup']['id'], - $this->context + true, ); - $priceRuleUuid = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $orContainerUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::RULE, 'customerGroupRule_orContainer_' . $price['customergroup']['id'], - $this->context + true, ); - $orContainerUuid = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $andContainerUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::RULE, 'customerGroupRule_andContainer_' . $price['customergroup']['id'], - $this->context + true, ); - $andContainerUuid = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $conditionUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::RULE, 'customerGroupRule_condition_' . $price['customergroup']['id'], - $this->context + true, ); - $conditionUuid = $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; $priceArray = $this->getPrice($price, $converted['tax']['taxRate']); @@ -1392,10 +1259,10 @@ private function getPrices(array $priceData, array $converted): array } $data = [ - 'id' => $productPriceRuleUuid, - 'productId' => $converted['id'], + 'id' => &$productPriceRuleUuid, + 'productId' => &$converted['id'], 'rule' => [ - 'id' => $priceRuleUuid, + 'id' => &$priceRuleUuid, 'name' => $price['customergroup']['description'], 'priority' => 0, 'moduleTypes' => [ @@ -1405,26 +1272,26 @@ private function getPrices(array $priceData, array $converted): array ], 'conditions' => [ [ - 'id' => $orContainerUuid, + 'id' => &$orContainerUuid, 'type' => (new OrRule())->getName(), 'value' => [], ], [ - 'id' => $andContainerUuid, + 'id' => &$andContainerUuid, 'type' => (new AndRule())->getName(), - 'parentId' => $orContainerUuid, + 'parentId' => &$orContainerUuid, 'value' => [], ], [ - 'id' => $conditionUuid, + 'id' => &$conditionUuid, 'type' => 'customerCustomerGroup', - 'parentId' => $andContainerUuid, + 'parentId' => &$andContainerUuid, 'position' => 1, 'value' => [ 'customerGroupIds' => [ - $customerGroupUuid, + &$customerGroupUuid, ], 'operator' => '=', ], @@ -1476,20 +1343,19 @@ private function setGivenProductTranslation(array &$data, array &$converted): vo $localeTranslation = []; - $localeTranslation['productId'] = $converted['id']; + $localeTranslation['productId'] = &$converted['id']; $this->convertValue($localeTranslation, 'name', $originalData, 'name'); $this->convertValue($localeTranslation, 'keywords', $originalData, 'keywords'); $this->convertValue($localeTranslation, 'description', $originalData, 'description_long'); $this->convertValue($localeTranslation, 'metaTitle', $originalData, 'metaTitle'); $this->convertValue($localeTranslation, 'packUnit', $originalData['detail'], 'packunit'); - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, + // only create and persist this mapping, no use in this converter + $this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_TRANSLATION, $this->oldProductId . ':' . $this->locale, - $this->context + true, ); - $this->mappingIds[] = $mapping['id']; $languageUuid = $this->languageLookup->get($this->locale, $this->context); $localeTranslation['languageId'] = $languageUuid; @@ -1512,35 +1378,32 @@ private function createMainCategoriesMapping(array $categories): array { $mainCategories = []; foreach ($categories as $category) { - $id = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $id = &$this->mappingServiceV2->getMapping( DefaultEntities::PRODUCT_MAIN_CATEGORY, $category['id'], - $this->context - )['entityId']; + true, + ); - $categoryId = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $categoryId = &$this->mappingServiceV2->getMapping( DefaultEntities::CATEGORY, $category['categoryId'], - $this->context - )['entityId']; + true, + ); - $salesChannelId = $this->mappingService->getOrCreateMapping( - $this->connectionId, + $salesChannelId = &$this->mappingServiceV2->getMapping( DefaultEntities::SALES_CHANNEL, $category['shopId'], - $this->context - )['entityId']; + true, + ); if (!$id || !$categoryId || !$salesChannelId) { continue; } $mainCategories[] = [ - 'id' => $id, - 'categoryId' => $categoryId, - 'salesChannelId' => $salesChannelId, + 'id' => &$id, + 'categoryId' => &$categoryId, + 'salesChannelId' => &$salesChannelId, ]; } @@ -1557,18 +1420,14 @@ private function getCategoryMapping(array $categories): array $categoryMapping = []; foreach ($categories as $category) { - $mapping = $this->mappingService->getMapping( - $this->connectionId, + $mappingUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::CATEGORY, $category['id'], - $this->context ); - if ($mapping === null) { - continue; - } - $categoryMapping[] = ['id' => (string) $mapping['entityId']]; - $this->mappingIds[] = $mapping['id']; + $categoryMapping[] = [ + 'id' => &$mappingUuid, + ]; } return $categoryMapping; @@ -1585,30 +1444,23 @@ private function getVisibilities(array $converted, array $shops): array $visibilities = []; foreach ($shops as $shop) { - $mapping = $this->mappingService->getMapping( - $this->connectionId, + $salesChannelUuid = &$this->mappingServiceV2->getMapping( DefaultEntities::SALES_CHANNEL, $shop, - $this->context ); - if ($mapping !== null) { - $salesChannelUuid = (string) $mapping['entityId']; - $this->mappingIds[] = $mapping['id']; - $mapping = $this->mappingService->getOrCreateMapping( - $this->connectionId, - DefaultEntities::PRODUCT_VISIBILITY, - $this->oldProductId . '_' . $shop, - $this->context - ); - $this->mappingIds[] = $mapping['id']; - $visibilities[] = [ - 'id' => (string) $mapping['entityId'], - 'productId' => $converted['id'], - 'salesChannelId' => $salesChannelUuid, - 'visibility' => ProductVisibilityDefinition::VISIBILITY_ALL, - ]; - } + $productVisibilityUuid = &$this->mappingServiceV2->getMapping( + DefaultEntities::PRODUCT_VISIBILITY, + $this->oldProductId . '_' . $shop, + true, + ); + + $visibilities[] = [ + 'id' => &$productVisibilityUuid, + 'productId' => &$converted['id'], + 'salesChannelId' => &$salesChannelUuid, + 'visibility' => ProductVisibilityDefinition::VISIBILITY_ALL, + ]; } return $visibilities;