-
Notifications
You must be signed in to change notification settings - Fork 22
Open
Description
I try us mapper with symfony discriminator, but it's not what i expected,
For example
// I have Source Interface or Abstract class
interface SourceInterface
{
}
/// And his impl
final readonly class SourceImpl implements SourceInterface
{
}
/// And i have target class for mapping, its Interface or Abstract too
interface TargetInterface
{
}
final readonly class TargetImpl implements TargetInterface
{
}In usage something like
$source = new Source();
// For interface
$result = $this->mapper->map($source, TargetInterface::class);
// And for abstract
$result = $this->mapper->map($source, AbstractTarget::class, (new MapperContext())->setConstructorArgument(AbstractTarget::class, 'property', 'value')->toArray();I try imp with event listener and replace target
#[\Attribute(\Attribute::TARGET_CLASS)]
final readonly class Discriminator
{
/**
* @param class-string $baseClass
* @param array<class-string, class-string> $map
*/
public function __construct(
public string $baseClass,
public array $map,
) { }
}
#[AsEventListener(GenerateMapperEvent::class)]
final readonly class DiscriminatorListener
{
public function __invoke(GenerateMapperEvent $event): void
{
if (!$event->mapperMetadata->targetReflectionClass) {
return;
}
$attributes = $event->mapperMetadata
->targetReflectionClass
->getAttributes(Discriminator::class);
if (count($attributes) === 0) {
return;
}
foreach ($attributes as $attr) {
$discriminatorAttribute = $attr->newInstance();
$baseClassRef = new ReflectionClass($discriminatorAttribute->baseClass);
if (!$event->mapperMetadata->sourceReflectionClass->isSubclassOf($baseClassRef)) {
continue;
}
if (!$baseClassRef->isInterface() && !$baseClassRef->isAbstract()) {
throw new BadMapDefinitionException(sprintf(
'Required `baseClass` should be abstract or interface in "%s" attribute on "%s" class.',
Discriminator::class,
$event->mapperMetadata->targetReflectionClass->getName(),
));
}
foreach ($discriminatorAttribute->map as $source => $target) {
$ref = new ReflectionClass($source);
if (!$ref->isSubclassOf($baseClassRef->getName())) {
throw new BadMapDefinitionException(sprintf(
'Required value of `map` should be subclass of %s in "%s" attribute on "%s" class.',
$baseClassRef->getName(),
Discriminator::class,
$event->mapperMetadata->targetReflectionClass->getName(),
));
}
if ($ref->getName() === $event->mapperMetadata->sourceReflectionClass->getName()) {
$event->mapperMetadata->target = $target;
}
}
}
}
}And it's work, but i still can't get default construct argument from context, because it's by from context by class name
RFC for example
interface SourceInterface
{
}
final readonly class SourceImpl implements SourceInterface
{
}
#[Discriminator(
SourceInterface::class, //Base class for source
[
SourceImpl::class => TargetImpl::class, // In mapping get check source class and his mapping
]
)]
interface TargetInterface
{
}
final readonly class TargetImpl implements TargetInterface
{
}
Metadata
Metadata
Assignees
Labels
No labels