Register a new module
The twocream Shopware Connector Bundle
offers two ways to implement an import module.
AbstractModule
is suitable for simple entities and is used, for example, for attribute imports. It is also used when you want to import flat data structures from the MDM area into your own Shopware entities.
AbstractSyncModule
is suitable for more complex entities, such as the Shopware product entity. It provides the option to create, update, or delete multiple entities during processing. For example, relational records like Shopware units of measure.
Structure of a simple module
Simple modules must inherit from this abstract class: Twocream\JsonImporter\Core\System\Import\Module\AbstractModule
<?php
namespace MyCustomExtension\Core\System\Import\Module;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Twocream\JsonImporter\Core\System\Import\Module\AbstractModule;
use Twocream\JsonImporter\Core\System\Import\Validation\Decision;
use Twocream\JsonImporter\Core\System\Import\Validation\Result;
use MyCustomExtension\Core\Content\Pimcore\MasterDataManagement\Video\VideoDefinition;
class VideoModule extends AbstractModule
{
public function getHandledPackage(): string
{
return 'videos';
}
protected function getEntityName(): string
{
return VideoDefinition::ENTITY_NAME;
}
protected function validateEntry(array $entry): array
{
$problems = [];
if (empty($entry['uuid'])) {
$problems[] = 'uuid';
}
if (empty($entry['id'])) {
$problems[] = 'id';
}
return $problems;
}
protected function store(Result $result): ?EntityWrittenContainerEvent
{
$records = [];
$videoRepository = $this->registry->getRepository('app_pimcore_video');
foreach ($result as $entry) {
if ($entry->getDecision() === Decision::DECISION_SKIP_RECORD) {
continue;
}
$translations = $this->service->prepareTranslation($entry['texts']['translations']);
$videoTranslations = $this->service->prepareTranslation($entry['video']['translations'], [
'youtube-link' => 'youtubeLink'
]);
$thumbnailTranslations = $this->service->prepareTranslation($entry['thumbnail']['translations'], [
'image' => 'thumbnailImage',
'title' => 'thumbnailTitle',
'alt-text' => 'thumbnailAltText'
]);
foreach ($translations as $key => $values) {
if (isset($videoTranslations[$key])) {
$translations[$key] = array_merge($values, $videoTranslations[$key]);
} else {
$translations[$key] = array_merge($values, ['youtubeLink' => null]);
}
if (isset($thumbnailTranslations[$key])) {
$translations[$key] = array_merge($translations[$key], $thumbnailTranslations[$key]);
} else {
$translations[$key] = array_merge(
$translations[$key],
['thumbnailImage' => null, 'thumbnailTitle' => null, 'thumbnailAltText' => null]
);
}
}
$records[] = [
'id' => $entry['uuid'],
'pimcoreId' => $entry['id'],
'key' => $entry['key'],
'type' => 'youtube',
'defaultLink' => $entry['video']['default-value'],
'translations' => $translations
];
}
if (!empty($records)) {
return $videoRepository->upsert($records, $this->context);
}
return null;
}
}
Structure of a more complex module
Complex modules must inherit from this abstract class: Twocream\JsonImporter\Core\System\Import\Module\AbstractSyncModule
namespace MyCustomExtension\Core\System\Import\Module;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Twocream\JsonImporter\Core\System\Import\Module\AbstractSyncModule;
use Twocream\JsonImporter\Core\System\Import\Validation\Decision;
use Twocream\JsonImporter\Core\System\Import\Validation\Result;
class ExampleModule extends AbstractSyncModule
{
public function getHandledPackage(): string
{
return 'example';
}
protected function getEntityName(): string
{
return ExampleDefinition::ENTITY_NAME;
}
protected function validateEntry(array $entry): array
{
$problems = [];
if (empty($entry['translations']['de_DE']['name'])) {
$problems[] = 'name';
}
return $problems;
}
protected function store(Result $result): ?EntityWrittenContainerEvent
{
foreach ($result as $entry) {
if ($entry->getDecision() === Decision::DECISION_SKIP_RECORD) {
continue;
}
if (!empty($entry['measurement-unit'])) {
$unitId = md5('unit-' . $entry['measurement-unit']);
if (!$this->isIdExist($unitId, UnitDefinition::ENTITY_NAME)) {
$this->syncs[UnitDefinition::ENTITY_NAME][SyncOperation::ACTION_UPSERT][] = [
'id' => $unitId,
'translations' => $this->service->prepareTranslation([
'de' => [
'name' => $entry['measurement-unit'],
'shortCode' => $entry['measurement-unit']
]
])
];
}
}
$translations = $this->service->prepareTranslation(
$entry['texts'],
[
'description' => 'description',
'name' => 'name',
]
);
$this->syncs[ProductDefinition::ENTITY_NAME][SyncOperation::ACTION_UPSERT][] = [
'id' => $entry['uuid'],
'pimcoreId' => $entry['id'],
'unitId' => $unitId,
'translations' => $translations,
'customFields' => [
'position' => $entry['custom-fields']['position'],
],
];
}
return $this->sync();
}
}
Explanation
The complex module builds upon the simple module, therefore the following definitions apply to both types.
Name | Description |
---|---|
getHandledPackage(): string | Unique package name, e.g., "product" |
getEntityName(): string | The name of the entity the module is intended for, e.g., "product" |
store(Result $result): ?EntityWrittenContainerEvent | Here, the content-related processing of data for import occurs |
canBeDeleted(): bool | Optionally, it can prevent data deletion |
isIdExist(string $id, string $entityName): bool | Helper method to check if a record with the given ID & entity already exists |
validateEntry(array $entry): array | Optionally, you can implement validation logic for imported data |
Register the module
New modules must be registered in a service configuration file. The service tag twocream_json_importer.module
must be used.
For structured configuration, it is recommended to create the file src/Resources/config/services/import.xml
.
This can then be included via an import into the central services.xml
.
<service id="MyCustomExtension\Core\System\Import\Module\ProductModule">
<tag name="twocream_json_importer.module"/>
</service>