Skip to content

IBX-8190: Update REST custom media type #2688

New issue

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

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

Already on GitHub? # to your account

Open
wants to merge 5 commits into
base: 5.0
Choose a base branch
from

Conversation

adriendupuis
Copy link
Contributor

@adriendupuis adriendupuis commented Apr 1, 2025

Question Answer
JIRA Ticket IBX-8190
Versions 5.0
Edition All
  • Move from removed ValueObjectVisitorDispatcher to new ValueObjectVisitorResolver.

Preview: Adding custom media type

Related PRs

This PR is the minimal mandatory change. In other PRs, some other optional improvement studies are made.

Checklist

  • Text renders correctly
  • Text has been checked with vale
  • Description metadata is up to date
  • Redirects cover removed/moved pages
  • Code samples are working
  • PHP code samples have been fixed with PHP CS fixer
  • Added link to this PR in relevant JIRA ticket or code PR

Move to ValueObjectVisitorDispatcher to ValueObjectVisitorResolver
Copy link

github-actions bot commented Apr 1, 2025

Property App\Rest\Output\ValueObjectVisitorResolver::$visitors type has no value type specified in iterable type array.

Method App\Rest\Output\ValueObjectVisitorResolver::__construct() has parameter $visitors with no value type specified in iterable type iterable.
@adriendupuis adriendupuis marked this pull request as ready for review April 2, 2025 06:59
@adriendupuis adriendupuis requested a review from barw4 April 2, 2025 06:59
Copy link

github-actions bot commented Apr 2, 2025

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/api/rest_api/config/services.yaml

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@41:``` yaml
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@42:services:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@43: #…

code_samples/api/rest_api/config/services.yaml

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@41:``` yaml
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@42:services:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@43: #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@44:[[= include_file('code_samples/api/rest_api/config/services.yaml', 28, 35) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@44:[[= include_file('code_samples/api/rest_api/config/services.yaml', 33, 41) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@45:```

001⫶services:
002⫶ #…
003⫶ App\Rest\ValueObjectVisitor\RestLocation:
004⫶ class: App\Rest\ValueObjectVisitor\RestLocation
005⫶ parent: Ibexa\Contracts\Rest\Output\ValueObjectVisitor
006⫶ arguments:
007⫶ $urlAliasService: '@ibexa.api.service.url_alias'
008⫶ tags:
009⫶ - { name: app.rest.output.value_object.visitor, type: Ibexa\Rest\Server\Values\RestLocation }

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@52:``` yaml
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@53:services:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@54: #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@45:```

001⫶services:
002⫶ #…
003⫶ App\Rest\ValueObjectVisitor\RestLocation:
004⫶ class: App\Rest\ValueObjectVisitor\RestLocation
005⫶ parent: Ibexa\Contracts\Rest\Output\ValueObjectVisitor
006⫶ arguments:
007⫶ $urlAliasService: '@ibexa.api.service.url_alias'
008⫶ tags:
009⫶ - { name: app.rest.output.value_object.visitor, type: Ibexa\Rest\Server\Values\RestLocation }

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@52:``` yaml
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@53:services:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@54: #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@55:[[= include_file('code_samples/api/rest_api/config/services.yaml', 22, 27) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@55:[[= include_file('code_samples/api/rest_api/config/services.yaml', 28, 32) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@56:```

001⫶services:
002⫶ #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@56:```

001⫶services:
002⫶ #…
003⫶    App\Rest\Output\ValueObjectVisitorDispatcher:
004⫶ class: App\Rest\Output\ValueObjectVisitorDispatcher
005⫶ arguments:
006⫶ - !tagged_iterator { tag: 'app.rest.output.value_object.visitor', index_by: 'type' }
007⫶ - '@Ibexa\Contracts\Rest\Output\ValueObjectVisitorDispatcher'
003⫶    App\Rest\Output\ValueObjectVisitorResolver:
004⫶ arguments:
005⫶ $visitors: !tagged_iterator { tag: 'app.rest.output.value_object.visitor', index_by: 'type' }
006⫶ $resolver: '@Ibexa\Contracts\Rest\Output\ValueObjectVisitorResolver'

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@67:``` yaml
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@68:parameters:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@69: #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@70:[[= include_file('code_samples/api/rest_api/config/services.yaml', 1, 3) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@71:services:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@72: #…

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@67:``` yaml
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@68:parameters:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@69: #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@70:[[= include_file('code_samples/api/rest_api/config/services.yaml', 1, 3) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@71:services:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@72: #…
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@73:[[= include_file('code_samples/api/rest_api/config/services.yaml', 6, 21) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@73:[[= include_file('code_samples/api/rest_api/config/services.yaml', 6, 27) =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@74:```

001⫶parameters:
002⫶ #…
003⫶ app.rest.output.visitor.xml.regexps: ['(^application/app\.api\.[A-Za-z]+\+xml$)']
004⫶ app.rest.output.visitor.json.regexps: ['(^application/app\.api\.[A-Za-z]+\+json$)']
005⫶
006⫶services:
007⫶ #…
008⫶ app.rest.output.visitor.xml:
009⫶ class: Ibexa\Contracts\Rest\Output\Visitor
010⫶ arguments:
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@74:```

001⫶parameters:
002⫶ #…
003⫶ app.rest.output.visitor.xml.regexps: ['(^application/app\.api\.[A-Za-z]+\+xml$)']
004⫶ app.rest.output.visitor.json.regexps: ['(^application/app\.api\.[A-Za-z]+\+json$)']
005⫶
006⫶services:
007⫶ #…
008⫶ app.rest.output.visitor.xml:
009⫶ class: Ibexa\Contracts\Rest\Output\Visitor
010⫶ arguments:
011⫶            - '@Ibexa\Rest\Output\Generator\Xml'
012⫶ - '@App\Rest\Output\ValueObjectVisitorDispatcher'
013⫶ tags:
014⫶ - { name: ibexa.rest.output.visitor, regexps: app.rest.output.visitor.xml.regexps, priority: 20 }
015⫶
016⫶ app.rest.output.visitor.json:
017⫶ class: Ibexa\Contracts\Rest\Output\Visitor
018⫶ arguments:
019⫶ - '@Ibexa\Rest\Output\Generator\Json'
020⫶ - '@App\Rest\Output\ValueObjectVisitorDispatcher'
021⫶ tags:
022⫶ - { name: ibexa.rest.output.visitor, regexps: app.rest.output.visitor.json.regexps, priority: 20 }
011⫶            $generator: '@Ibexa\Rest\Output\Generator\Xml'
012⫶ $normalizer: '@ibexa.rest.serializer'
013⫶ $encoder: '@ibexa.rest.serializer.encoder.xml'
014⫶ $valueObjectVisitorResolver: '@App\Rest\Output\ValueObjectVisitorResolver'
015⫶ $format: 'xml'
016⫶ tags:
017⫶ - { name: ibexa.rest.output.visitor, regexps: app.rest.output.visitor.xml.regexps, priority: 20 }
018⫶
019⫶ app.rest.output.visitor.json:
020⫶ class: Ibexa\Contracts\Rest\Output\Visitor
021⫶ arguments:
022⫶ $generator: '@Ibexa\Rest\Output\Generator\Json'
023⫶ $normalizer: '@ibexa.rest.serializer'
024⫶ $encoder: '@ibexa.rest.serializer.encoder.json'
025⫶ $valueObjectVisitorResolver: '@App\Rest\Output\ValueObjectVisitorResolver'
026⫶ $format: 'json'
027⫶ tags:
028⫶ - { name: ibexa.rest.output.visitor, regexps: app.rest.output.visitor.json.regexps, priority: 20 }

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@48:``` yaml
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@49:services:
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@50: #…

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@48:``` yaml
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@49:services:
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@50: #…
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@51:[[= include_file('code_samples/api/rest_api/config/services.yaml', 36, 42) =]]
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@51:[[= include_file('code_samples/api/rest_api/config/services.yaml', 41, 47) =]]
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@52:```

001⫶services:
002⫶ #…
003⫶ App\Rest\Controller\:
004⫶ resource: '../src/Rest/Controller/'
005⫶ parent: Ibexa\Rest\Server\Controller
006⫶ autowire: true
007⫶ autoconfigure: true
008⫶ tags: [ 'controller.service_arguments' ]

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@98:``` yaml
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@99:services:
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@100: #…
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@52:```

001⫶services:
002⫶ #…
003⫶ App\Rest\Controller\:
004⫶ resource: '../src/Rest/Controller/'
005⫶ parent: Ibexa\Rest\Server\Controller
006⫶ autowire: true
007⫶ autoconfigure: true
008⫶ tags: [ 'controller.service_arguments' ]

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@98:``` yaml
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@99:services:
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@100: #…
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@101:[[= include_file('code_samples/api/rest_api/config/services.yaml', 43, 48) =]]
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@101:[[= include_file('code_samples/api/rest_api/config/services.yaml', 48, 53) =]]
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@102:```

001⫶services:
002⫶ #…
003⫶ App\Rest\ValueObjectVisitor\Greeting:
004⫶ parent: Ibexa\Contracts\Rest\Output\ValueObjectVisitor
005⫶ tags:
006⫶ - { name: ibexa.rest.output.value_object.visitor, type: App\Rest\Values\Greeting }

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@120:``` yaml
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@121:services:
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@122: #…
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@102:```

001⫶services:
002⫶ #…
003⫶ App\Rest\ValueObjectVisitor\Greeting:
004⫶ parent: Ibexa\Contracts\Rest\Output\ValueObjectVisitor
005⫶ tags:
006⫶ - { name: ibexa.rest.output.value_object.visitor, type: App\Rest\Values\Greeting }

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@120:``` yaml
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@121:services:
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@122: #…
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@123:[[= include_file('code_samples/api/rest_api/config/services.yaml', 48, 53) =]]
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@123:[[= include_file('code_samples/api/rest_api/config/services.yaml', 53, 58) =]]
docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@124:```

001⫶services:
002⫶ #…
003⫶ App\Rest\InputParser\GreetingInput:
004⫶ parent: Ibexa\Rest\Server\Common\Parser
005⫶ tags:
006⫶ - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.GreetingInput }


code_samples/api/rest_api/src/Rest/Output/ValueObjectVisitorDispatcher.php

docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md@124:```

001⫶services:
002⫶ #…
003⫶ App\Rest\InputParser\GreetingInput:
004⫶ parent: Ibexa\Rest\Server\Common\Parser
005⫶ tags:
006⫶ - { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.GreetingInput }


code_samples/api/rest_api/src/Rest/Output/ValueObjectVisitorDispatcher.php


code_samples/api/rest_api/src/Rest/Output/ValueObjectVisitorResolver.php

docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@58:``` php
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@58:``` php
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@59:[[= include_file('code_samples/api/rest_api/src/Rest/Output/ValueObjectVisitorDispatcher.php') =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@59:[[= include_file('code_samples/api/rest_api/src/Rest/Output/ValueObjectVisitorResolver.php') =]]
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@60:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\Rest\Output;
004⫶
docs/api/rest_api/extending_rest_api/adding_custom_media_type.md@60:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\Rest\Output;
004⫶
005⫶use Ibexa\Contracts\Rest\Output\Generator;
006⫶use Ibexa\Contracts\Rest\Output\ValueObjectVisitorDispatcher as BaseValueObjectVisitorDispatcher;
007⫶use Ibexa\Contracts\Rest\Output\Visitor;
008⫶
009⫶class ValueObjectVisitorDispatcher // extends BaseValueObjectVisitorDispatcher TODO: Rewrite this example in https://issues.ibexa.co/browse/IBX-8190
010⫶{
005⫶use Ibexa\Contracts\Rest\Output\ValueObjectVisitor;
006⫶use Ibexa\Contracts\Rest\Output\ValueObjectVisitorResolverInterface;
007⫶
008⫶class ValueObjectVisitorResolver implements ValueObjectVisitorResolverInterface
009⫶{
010⫶ /** @var array<string, ValueObjectVisitor> */
011⫶    private array $visitors;
012⫶
011⫶    private array $visitors;
012⫶
013⫶    private BaseValueObjectVisitorDispatcher $valueObjectVisitorDispatcher;
013⫶    private ValueObjectVisitorResolverInterface $valueObjectVisitorResolver;
014⫶
014⫶
015⫶    private Visitor $outputVisitor;
016⫶
017⫶ private Generator $outputGenerator;
018⫶
019⫶ public function __construct(iterable $visitors, BaseValueObjectVisitorDispatcher $valueObjectVisitorDispatcher)
020⫶ {
021⫶ $this->visitors = [];
022⫶ foreach ($visitors as $type => $visitor) {
023⫶ $this->visitors[$type] = $visitor;
024⫶ }
025⫶ $this->valueObjectVisitorDispatcher = $valueObjectVisitorDispatcher;
026⫶ }
027⫶
028⫶ public function setOutputVisitor(Visitor $outputVisitor): void
029⫶ {
030⫶ $this->outputVisitor = $outputVisitor;
031⫶ $this->valueObjectVisitorDispatcher->setOutputVisitor($outputVisitor);
032⫶ }
033⫶
034⫶ public function setOutputGenerator(Generator $outputGenerator): void
035⫶ {
036⫶ $this->outputGenerator = $outputGenerator;
037⫶ $this->valueObjectVisitorDispatcher->setOutputGenerator($outputGenerator);
038⫶ }
039⫶
040⫶ public function visit($data)
041⫶ {
042⫶ $className = get_class($data);
043⫶ if (isset($this->visitors[$className])) {
044⫶ return $this->visitors[$className]->visit($this->outputVisitor, $this->outputGenerator, $data);
045⫶ }
046⫶
047⫶ return $this->valueObjectVisitorDispatcher->visit($data);
048⫶ }
049⫶}


code_samples/api/rest_api/src/Rest/Output/ValueObjectVisitorResolver.php
015⫶    /** @param iterable<string, ValueObjectVisitor> $visitors */
016⫶ public function __construct(iterable $visitors, ValueObjectVisitorResolverInterface $resolver)
017⫶ {
018⫶ $this->visitors = [];
019⫶ foreach ($visitors as $type => $visitor) {
020⫶ $this->visitors[$type] = $visitor;
021⫶ }
022⫶ $this->valueObjectVisitorResolver = $resolver;
023⫶ }
024⫶
025⫶ public function resolveValueObjectVisitor(object $object): ?ValueObjectVisitor
026⫶ {
027⫶ $className = get_class($object);
028⫶ if (isset($this->visitors[$className])) {
029⫶ return $this->visitors[$className];
030⫶ }
031⫶
032⫶ return $this->valueObjectVisitorResolver->resolveValueObjectVisitor($object);
033⫶ }
034⫶}


Download colorized diff

@mnocon mnocon changed the base branch from master to 5.0 May 19, 2025 07:25
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant