Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add dynamic interface resolution #560

Closed
wants to merge 3 commits into from
Closed

add dynamic interface resolution #560

wants to merge 3 commits into from

Conversation

mastir
Copy link

@mastir mastir commented Sep 9, 2024

Made interface resolvers implementation for #558 . This implementation allows to add discriminator properties to normalized array and resove actual class based on descriminator props

Example:

interface Container{}

class BoxContainer implements Container{
    function __construct(int $width, int $height){}
}

class SquereContainer implements Container{
    function __construct(int $width, int $height){}
}

class CircleContainer implements Container{
    function __construct(int $radius){}
}

class MyResolver(){
    public function resolve(string $interface, ?array $props) : ?string
    {
        if ($interface === 'Container'){
            return match($props['type']){
                'box' => BoxContainer::class,
                'squere' => SquereContainer::class,
                'circle' => CircleContainer::class,
            }
        }
    }
    
    public function getResolverProps(string $interface) : array
    {
        return ['type'];
    }
    
    public function transform(object $input, callable $next) : array
    {
         $result = $next($input);
         if ($input instanceOf ContainerInterface){
              $result['type'] = match(get_class($input)){
                 BoxContainer::class => 'box',
                SquereContainer::class => 'squere',
                CircleContainer::class => 'circle',
             }
         }
         return  $result;
    }
}

$mapperBuilder->withInterfaceResolver(new MyResolver());
$normalized  = $normalizer->normalize(new BoxContainer(3,5)); // ['type'=>'box', 'width'=>3, 'height'=>5]
$object = $mapper->map(Container::class, $normalized); //new BoxContainer(3,5)

This can partialy be done with infer / transform, but some validations faild due too extra fields and dynamic interface reading is not possible. In my project i use Attribute on interfaces to declare type mapping and discriminator field:

#[TypedInterface([
    'box' => BoxContainer::class,
    'squere' => SquereContainer::class,
    'circle' => CircleContainer::class,
], 'conteiner_type')]
interface Container{
...

class InterfaceObjectResolver implements \CuyZ\Valinor\InterfaceResolver
{

    public function resolve(string $interface, ?array $props) : ?string
    {
        [$type_map, $discriminator] = $this->readAttributes($interface);
        if (!$type_map){
            return null;
        }
        return $type_map[$props[$discriminator]];
    }
...

@romm
Copy link
Member

romm commented Sep 18, 2024

This feature already exists in the library, see #558 (comment)

Thanks for the effort, though! I'll have to think about making documentation more precise about it.

@romm romm closed this Sep 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants