Skip to content

Commit

Permalink
Added support to create variants on object creation (#375)
Browse files Browse the repository at this point in the history
* Added support to create variants on object creation

* Apply suggestions from code review

Co-authored-by: Sebastian Blank <sebastian.bl@gmx.de>

* Added error handling when changing existing variants

As the parent can be changed for variants this is now catched, as a variant cannot change its
parent anymore.

* Added support to create variants on object creation

* Added error handling when changing existing variants

As the parent can be changed for variants this is now catched, as a variant cannot change its
parent anymore.

* Removed unecessary translations

* Addressed some qodana warnings

* Allowing variants to be parents of variants of the same class

* Apply php-cs-fixer changes

* fixup! Allowing variants to be parents of variants of the same class

* Added check if parent has changed

* Added individual exceptions when variant type cannot be set

* Apply php-cs-fixer changes

* fixup! Added individual exceptions when variant type cannot be set

* Allowing variants to be changed to objects

* fixup! Allowing variants to be changed to objects

---------

Co-authored-by: Sebastian Blank <sebastian.bl@gmx.de>
Co-authored-by: turbo-ele <turbo-ele@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 16, 2024
1 parent bad738e commit c43691a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/Resolver/Location/FindParentStrategy.php
Expand Up @@ -15,9 +15,12 @@

namespace Pimcore\Bundle\DataImporterBundle\Resolver\Location;

use Exception;
use Pimcore\Bundle\DataImporterBundle\Exception\InvalidConfigurationException;
use Pimcore\Bundle\DataImporterBundle\Exception\InvalidInputException;
use Pimcore\Bundle\DataImporterBundle\Tool\DataObjectLoader;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\DataObject\ClassDefinition;
use Pimcore\Model\Element\ElementInterface;

Expand Down Expand Up @@ -57,6 +60,8 @@ class FindParentStrategy implements LocationStrategyInterface
*/
protected $attributeLanguage;

protected bool $saveAsVariant = false;

public function __construct(protected DataObjectLoader $dataObjectLoader)
{
}
Expand All @@ -75,6 +80,8 @@ public function setSettings(array $settings): void
throw new InvalidConfigurationException('Empty find strategy.');
}

$this->saveAsVariant = isset($settings['asVariant']) && $settings['asVariant'] === 'on';

$this->findStrategy = $settings['findStrategy'];

if ($this->findStrategy == self::FIND_BY_ATTRIBUTE) {
Expand Down Expand Up @@ -129,6 +136,20 @@ public function updateParent(ElementInterface $element, array $inputData): Eleme
}

if ($newParent) {
if (
$newParent->getType() === AbstractObject::OBJECT_TYPE_VARIANT &&
(
$element->getType() !== AbstractObject::OBJECT_TYPE_VARIANT ||
$element::class !== $newParent::class
)
) {
throw new InvalidInputException(
"An element can only have a variant as a parent if it's a variant itself and of the same class."
);
}

$this->setElementType($element, $newParent);

return $element->setParent($newParent);
}

Expand All @@ -138,4 +159,62 @@ public function updateParent(ElementInterface $element, array $inputData): Eleme
protected function loadById()
{
}

/**
* @throws InvalidInputException
*/
private function setElementType(ElementInterface $element, DataObject | ElementInterface $newParent): void
{
// Check if element should be saved as a variant if not already.
if (
$this->saveAsVariant && $element->getType() !== AbstractObject::OBJECT_TYPE_VARIANT
) {
if (
!$element instanceof DataObject\Concrete
|| $element::class !== $newParent::class
) {
throw new InvalidInputException(
'Changing type not possible: Only concrete objects of the same class can be saved as a variant.'
);
}

if ($element->hasChildren()) {
throw new InvalidInputException(
'Changing type not possible: Only objects without any children can be saved as a variant.'
);
}

if (!$this->getElementClassDefinition($element)?->getAllowVariants()) {
throw new InvalidInputException(
sprintf(
'Changing type not possible: Class `%s` is not configured to allow the creation of variants.',
$this->getElementClassDefinition($element)?->getName(),
)
);
}

$element->setType(AbstractObject::OBJECT_TYPE_VARIANT);
} elseif (
!$this->saveAsVariant
&& $element instanceof AbstractObject
&& $element->getType() === AbstractObject::OBJECT_TYPE_VARIANT
) {
if ($newParent->getType() === AbstractObject::OBJECT_TYPE_VARIANT) {
throw new InvalidInputException(
'Changing type not possible: An object cannot be a child of a variant.'
);
}

$element->setType(AbstractObject::OBJECT_TYPE_OBJECT);
}
}

private function getElementClassDefinition(DataObject\Concrete $element): ?ClassDefinition
{
try {
return $element->getClass();
} catch (Exception) {
return null;
}
}
}
16 changes: 16 additions & 0 deletions src/Resolver/Resolver.php
Expand Up @@ -15,10 +15,12 @@

namespace Pimcore\Bundle\DataImporterBundle\Resolver;

use Pimcore\Bundle\DataImporterBundle\Exception\InvalidInputException;
use Pimcore\Bundle\DataImporterBundle\Resolver\Factory\FactoryInterface;
use Pimcore\Bundle\DataImporterBundle\Resolver\Load\LoadStrategyInterface;
use Pimcore\Bundle\DataImporterBundle\Resolver\Location\LocationStrategyInterface;
use Pimcore\Bundle\DataImporterBundle\Resolver\Publish\PublishStrategyInterface;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\Element\ElementInterface;

class Resolver
Expand Down Expand Up @@ -134,6 +136,9 @@ public function loadElementByIdentifier($identifier): ?ElementInterface
return $this->getLoadingStrategy()->loadElementByIdentifier($identifier);
}

/**
* @throws InvalidInputException
*/
public function loadOrCreateAndPrepareElement(array $inputData, bool $createNew = true): ?ElementInterface
{
$element = $this->loadElement($inputData);
Expand All @@ -149,7 +154,18 @@ public function loadOrCreateAndPrepareElement(array $inputData, bool $createNew
$this->getCreateLocationStrategy()->updateParent($element, $inputData);
$justCreated = true;
} else {
$oldParentId = $element->getParentId();
$this->getLocationUpdateStrategy()->updateParent($element, $inputData);

// The parent of a variant cannot be changed anymore.
if (
$oldParentId !== $element->getParentId()
&& $element->getType() === AbstractObject::OBJECT_TYPE_VARIANT
) {
throw new InvalidInputException(
"Element with id `{$element->getId()}` is a variant and cannot change its parent anymore"
);
}
}

$this->getPublishingStrategy()->updatePublishState($element, $justCreated, $inputData);
Expand Down
Expand Up @@ -154,6 +154,12 @@ pimcore.plugin.pimcoreDataImporterBundle.configuration.components.resolver.locat
fieldLabel: t('plugin_pimcore_datahub_data_importer_configpanel_fallback_path'),
name: this.dataNamePrefix + 'fallbackPath',
value: this.data.fallbackPath
},
{
xtype: 'checkbox',
fieldLabel: t('plugin_pimcore_datahub_data_importer_configpanel_as_variant'),
name: this.dataNamePrefix + 'asVariant',
value: this.data.asVariant
}
]
});
Expand Down
1 change: 1 addition & 0 deletions src/Resources/translations/admin.en.yml
Expand Up @@ -64,6 +64,7 @@ plugin_pimcore_datahub_data_importer_configpanel_element_creation: Element Creat
plugin_pimcore_datahub_data_importer_configpanel_create_location_strategy: Location Strategy
plugin_pimcore_datahub_data_importer_configpanel_fallback_path: Fallback Path
plugin_pimcore_datahub_data_importer_configpanel_find_strategy: Find Strategy
plugin_pimcore_datahub_data_importer_configpanel_as_variant: As Variant
plugin_pimcore_datahub_data_importer_configpanel_createLocationStrategy.type_findParent: Find Parent
plugin_pimcore_datahub_data_importer_configpanel_createLocationStrategy.type_findOrCreateFolder: Find or Create Folder
plugin_pimcore_datahub_data_importer_configpanel_createLocationStrategy.type_noChange: No Change
Expand Down

0 comments on commit c43691a

Please sign in to comment.