How to Use a Draft Extension
An extension is a service that enables you to modify entity data when creating a draft entity. The extension is responsible for filters and matchers load. If the entity does not fit the extension criteria, it ignores the execution and does not change the entity.
How to Create an Extension
To create an extension, you must create a class, extend it from AbstractDuplicatorExtension
, and register it as a service.
Add the oro_draft.duplicator.extension
tag to your extension configuration.
Extension
To simplify the implementation, you can use the default DuplicatorExtension
extension and register it in the configuration.
Example:
oro_draft.duplicator_extension.localization_extension:
class: Oro\Bundle\DraftBundle\Duplicator\Extension\DuplicatorExtension
arguments:
- !service
class: DeepCopy\Matcher\PropertyTypeMatcher
arguments: ['Oro\Bundle\LocaleBundle\Entity\Localization']
- !service
class: DeepCopy\Filter\KeepFilter
tags:
- { name: oro_draft.duplicator.extension, priority: 0 }
Note
Keep your extension priorities in mind. If two extensions have one area of responsibility, then the higher priority extension will apply. All other extensions will be ignored.
context - use context parameter to control the expansion workflow. In the process, you will find actions that use the extension only at the draft creation stage and do not use it during the draft publication.
Default actions:
DraftManager::ACTION_CREATE_DRAFT.
DraftManager::ACTION_PUBLISH_DRAFT.
The example below illustrates the way to use context. We only update the draft entity creation date. The draft entity publication date remains unchanged.
namespace Oro\Bundle\DraftBundle\Duplicator\Extension;
use DeepCopy\Filter\Filter;
use DeepCopy\Matcher\Matcher;
use DeepCopy\Matcher\PropertyTypeMatcher;
use Oro\Bundle\DraftBundle\Duplicator\Filter\DateTimeFilter;
use Oro\Bundle\DraftBundle\Entity\DraftableInterface;
use Oro\Bundle\DraftBundle\Manager\DraftManager;
/**
* Responsible for copying behavior of DateTime type parameters.
*/
class DateTimeExtension extends AbstractDuplicatorExtension
{
public function getFilter(): Filter
{
return new DateTimeFilter();
}
public function getMatcher(): Matcher
{
return new PropertyTypeMatcher(\DateTime::class);
}
/**
* @inheritDoc
*/
public function isSupport(DraftableInterface $source): bool
{
return $this->getContext()->offsetGet('action') === DraftManager::ACTION_CREATE_DRAFT;
}
}
Filter
The filter is responsible for the entity data modification.
The example below illustrates the way to create and use the filter. This filter uses dependency to update the owner of a draft entity.
namespace Oro\Bundle\DraftBundle\Duplicator\Filter;
use Oro\Bundle\DraftBundle\Entity\DraftableInterface;
use Oro\Component\Duplicator\Filter\Filter;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
/**
* Responsible for updating draft owner field.
*/
class OwnerFilter implements Filter
{
private TokenStorageInterface $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
/**
* @param DraftableInterface $object
* @param string $property
* @param callable $objectCopier
*/
public function apply($object, $property, $objectCopier): void
{
$user = $this->tokenStorage->getToken()->getUser();
$object->setDraftOwner($user);
}
}
Matcher
Matcher indicates the criteria that the filter is following to work successfully.
As an example, consider a matcher that takes properties names. This enables you to use one filter for multiple properties.
namespace Oro\Bundle\DraftBundle\Duplicator\Matcher;
use DeepCopy\Matcher\Matcher;
/**
* Determines whether a filter can be applied to the specified properties
*/
class PropertiesNameMatcher implements Matcher
{
/**
* @var string[]
*/
private $properties;
/**
* @param string[] $properties
*/
public function __construct(array $properties = [])
{
$this->properties = $properties;
}
/**
* @inheritDoc
*/
public function matches($object, $property): bool
{
return in_array($property, $this->properties);
}
}