diff --git a/.ddev/test/files/src/t3apinews/Classes/Domain/Model/News.php b/.ddev/test/files/src/t3apinews/Classes/Domain/Model/News.php index ef52d8c..784bff8 100644 --- a/.ddev/test/files/src/t3apinews/Classes/Domain/Model/News.php +++ b/.ddev/test/files/src/t3apinews/Classes/Domain/Model/News.php @@ -287,6 +287,7 @@ class News extends \GeorgRinger\News\Domain\Model\News * "api_get_item_t3apinews_news", * "api_patch_item_t3apinews_news", * }) + * @T3api\ORM\Cascade("persist") */ protected $falMedia; diff --git a/Classes/Attribute/AsApiResourcePathProvider.php b/Classes/Attribute/AsApiResourcePathProvider.php new file mode 100644 index 0000000..023837f --- /dev/null +++ b/Classes/Attribute/AsApiResourcePathProvider.php @@ -0,0 +1,21 @@ + ['priority' => $priority]], + ] + ); + } +} diff --git a/Classes/Attribute/AsOperationHandler.php b/Classes/Attribute/AsOperationHandler.php new file mode 100644 index 0000000..a93a9d8 --- /dev/null +++ b/Classes/Attribute/AsOperationHandler.php @@ -0,0 +1,21 @@ + ['priority' => $priority]], + ] + ); + } +} diff --git a/Classes/Attribute/AsProcessor.php b/Classes/Attribute/AsProcessor.php new file mode 100644 index 0000000..80b5391 --- /dev/null +++ b/Classes/Attribute/AsProcessor.php @@ -0,0 +1,21 @@ + ['priority' => $priority]], + ] + ); + } +} diff --git a/Classes/Attribute/AsSerializerHandler.php b/Classes/Attribute/AsSerializerHandler.php new file mode 100644 index 0000000..26ee1d1 --- /dev/null +++ b/Classes/Attribute/AsSerializerHandler.php @@ -0,0 +1,21 @@ + ['priority' => $priority]], + ] + ); + } +} diff --git a/Classes/Attribute/AsSerializerObjectConstructor.php b/Classes/Attribute/AsSerializerObjectConstructor.php new file mode 100644 index 0000000..ccd9338 --- /dev/null +++ b/Classes/Attribute/AsSerializerObjectConstructor.php @@ -0,0 +1,21 @@ + ['priority' => $priority]], + ] + ); + } +} diff --git a/Classes/Attribute/AsSerializerSubscriber.php b/Classes/Attribute/AsSerializerSubscriber.php new file mode 100644 index 0000000..44daeb5 --- /dev/null +++ b/Classes/Attribute/AsSerializerSubscriber.php @@ -0,0 +1,21 @@ + ['priority' => $priority]], + ] + ); + } +} diff --git a/Classes/Configuration/Configuration.php b/Classes/Configuration/Configuration.php index 1ea45ec..3dd8908 100644 --- a/Classes/Configuration/Configuration.php +++ b/Classes/Configuration/Configuration.php @@ -11,46 +11,42 @@ class Configuration { public static function getOperationHandlers(): array { - return self::getClassNamesSortedByPriority($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['operationHandlers']); + trigger_error('Configuration::getOperationHandlers() will be removed in t3api v4.0.', E_USER_DEPRECATED); + return self::getClassNamesSortedByPriority($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['operationHandlers'] ?? []); } public static function getProcessors(): array { - return self::getClassNamesSortedByPriority($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['processors']); + trigger_error('Configuration::getProcessors() will be removed in t3api v4.0.', E_USER_DEPRECATED); + return self::getClassNamesSortedByPriority($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['processors'] ?? []); } - public static function getCollectionResponseClass(): string + public static function getSerializerHandlers(): array { - return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['collectionResponseClass']; + trigger_error('Configuration::getSerializerHandlers() will be removed in t3api v4.0.', E_USER_DEPRECATED); + return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerHandlers'] ?? []; } - public static function getCors(): array + public static function getSerializerSubscribers(): array { - return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['cors']; + trigger_error('Configuration::getSerializerSubscribers() will be removed in t3api v4.0.', E_USER_DEPRECATED); + return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerSubscribers'] ?? []; } - protected static function getClassNamesSortedByPriority(?array $items): array + public static function getSerializerObjectConstructors(): array { - $items = $items ?? []; - $items = array_map( - static function ($class, $priority): array { - return [ - 'className' => $class, - 'priority' => is_numeric($priority) ? $priority : 50, - ]; - }, - array_keys($items), - $items - ); + trigger_error('Configuration::getSerializerObjectConstructors() will be removed in t3api v4.0.', E_USER_DEPRECATED); + return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerObjectConstructors'] ?? []; + } - usort( - $items, - static function (array $itemA, array $itemB): int { - return $itemB['priority'] <=> $itemA['priority']; - } - ); + public static function getCollectionResponseClass(): string + { + return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['collectionResponseClass']; + } - return array_column($items, 'className'); + public static function getCors(): array + { + return $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['cors']; } /** @@ -58,7 +54,10 @@ static function (array $itemA, array $itemB): int { */ public static function getApiResourcePathProviders(): \Generator { - $apiResourcePathProvidersClasses = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['apiResourcePathProviders']; + trigger_error('Configuration::getApiResourcePathProviders() will be removed in t3api v4.0.', E_USER_DEPRECATED); + + $apiResourcePathProvidersClasses + = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['apiResourcePathProviders'] ?? []; foreach ($apiResourcePathProvidersClasses as $apiResourcePathProviderClass) { $apiResourcePathProvider = GeneralUtility::makeInstance($apiResourcePathProviderClass); @@ -77,4 +76,28 @@ public static function getApiResourcePathProviders(): \Generator yield $apiResourcePathProvider; } } + + protected static function getClassNamesSortedByPriority(?array $items): array + { + $items = $items ?? []; + $items = array_map( + static function ($class, $priority): array { + return [ + 'className' => $class, + 'priority' => is_numeric($priority) ? $priority : 50, + ]; + }, + array_keys($items), + $items + ); + + usort( + $items, + static function (array $itemA, array $itemB): int { + return $itemB['priority'] <=> $itemA['priority']; + } + ); + + return array_column($items, 'className'); + } } diff --git a/Classes/Dispatcher/AbstractDispatcher.php b/Classes/Dispatcher/AbstractDispatcher.php index b1e78e1..d19c4b9 100644 --- a/Classes/Dispatcher/AbstractDispatcher.php +++ b/Classes/Dispatcher/AbstractDispatcher.php @@ -6,11 +6,12 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface; -use SourceBroker\T3api\Configuration\Configuration; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Domain\Repository\ApiResourceRepository; use SourceBroker\T3api\Event\AfterProcessOperationEvent; use SourceBroker\T3api\Exception\RouteNotFoundException; +use SourceBroker\T3api\Factory\OperationHandlerCollectionFactory; +use SourceBroker\T3api\Factory\ProcessorsCollectionFactory; use SourceBroker\T3api\OperationHandler\OperationHandlerInterface; use SourceBroker\T3api\Processor\ProcessorInterface; use SourceBroker\T3api\Serializer\ContextBuilder\DeserializationContextBuilder; @@ -21,7 +22,6 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException as SymfonyResourceNotFoundException; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; -use TYPO3\CMS\Core\Utility\GeneralUtility; abstract class AbstractDispatcher { @@ -35,20 +35,32 @@ abstract class AbstractDispatcher protected DeserializationContextBuilder $deserializationContextBuilder; + protected OperationHandlerCollectionFactory $operationHandlerCollectionFactory; + + protected ProcessorsCollectionFactory $processorsCollectionFactory; + public function __construct( SerializerService $serializerService, ApiResourceRepository $apiResourceRepository, SerializationContextBuilder $serializationContextBuilder, DeserializationContextBuilder $deserializationContextBuilder, - EventDispatcherInterface $eventDispatcherInterface + EventDispatcherInterface $eventDispatcherInterface, + OperationHandlerCollectionFactory $operationHandlerCollectionFactory, + ProcessorsCollectionFactory $processorsCollectionFactory ) { $this->serializerService = $serializerService; $this->apiResourceRepository = $apiResourceRepository; $this->serializationContextBuilder = $serializationContextBuilder; $this->deserializationContextBuilder = $deserializationContextBuilder; $this->eventDispatcher = $eventDispatcherInterface; + $this->operationHandlerCollectionFactory = $operationHandlerCollectionFactory; + $this->processorsCollectionFactory = $processorsCollectionFactory; + + $this->init(); } + abstract protected function init(): void; + /** * @throws RouteNotFoundException * @throws \Exception @@ -104,8 +116,7 @@ protected function processOperation( ); } - /** @var OperationHandlerInterface $handler */ - $handler = GeneralUtility::makeInstance(array_shift($handlers)); + $handler = array_shift($handlers); $result = $handler->handle($operation, $request, $route, $response); $afterProcessOperationEvent = new AfterProcessOperationEvent( @@ -126,20 +137,19 @@ protected function processOperation( protected function getHandlersSupportingOperation(OperationInterface $operation, Request $request): array { return array_filter( - Configuration::getOperationHandlers(), - static function (string $operationHandlerClass) use ($operation, $request) { - if (!is_subclass_of($operationHandlerClass, OperationHandlerInterface::class, true)) { + $this->operationHandlerCollectionFactory->get(), + static function ($operationHandler) use ($operation, $request) { + if (!$operationHandler instanceof OperationHandlerInterface) { throw new \RuntimeException( sprintf( 'Operation handler `%s` needs to be an instance of `%s`', - $operationHandlerClass, + $operationHandler::class, OperationHandlerInterface::class ), 1591018489732 ); } - - return call_user_func($operationHandlerClass . '::supports', $operation, $request); + return $operationHandler::supports($operation, $request); } ); } @@ -147,21 +157,19 @@ static function (string $operationHandlerClass) use ($operation, $request) { protected function callProcessors(Request $request, ResponseInterface $response): void { array_filter( - Configuration::getProcessors(), - static function (string $processorClass) use ($request, &$response) { - if (!is_subclass_of($processorClass, ProcessorInterface::class, true)) { + $this->processorsCollectionFactory->get(), + static function ($processor) use ($request, &$response) { + if (!$processor instanceof ProcessorInterface) { throw new \RuntimeException( sprintf( 'Process `%s` needs to be an instance of `%s`', - $processorClass, + $processor::class, ProcessorInterface::class ), 1603705384 ); } - /** @var ProcessorInterface $processor */ - $processor = GeneralUtility::makeInstance($processorClass); $processor->process($request, $response); } ); diff --git a/Classes/Dispatcher/Bootstrap.php b/Classes/Dispatcher/Bootstrap.php index f1f6086..0feb040 100644 --- a/Classes/Dispatcher/Bootstrap.php +++ b/Classes/Dispatcher/Bootstrap.php @@ -4,15 +4,10 @@ namespace SourceBroker\T3api\Dispatcher; -use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use SourceBroker\T3api\Domain\Repository\ApiResourceRepository; use SourceBroker\T3api\Exception\ExceptionInterface; -use SourceBroker\T3api\Serializer\ContextBuilder\DeserializationContextBuilder; -use SourceBroker\T3api\Serializer\ContextBuilder\SerializationContextBuilder; use SourceBroker\T3api\Service\RouteService; -use SourceBroker\T3api\Service\SerializerService; use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\Routing\Exception\ResourceNotFoundException; @@ -29,20 +24,8 @@ class Bootstrap extends AbstractDispatcher protected HttpFoundationFactory $httpFoundationFactory; - public function __construct( - SerializerService $serializerService, - ApiResourceRepository $apiResourceRepository, - SerializationContextBuilder $serializationContextBuilder, - DeserializationContextBuilder $deserializationContextBuilder, - EventDispatcherInterface $eventDispatcherInterface - ) { - parent::__construct( - $serializerService, - $apiResourceRepository, - $serializationContextBuilder, - $deserializationContextBuilder, - $eventDispatcherInterface, - ); + protected function init(): void + { $this->response = new Response('php://temp', 200, ['Content-Type' => 'application/ld+json']); $this->httpFoundationFactory = GeneralUtility::makeInstance(HttpFoundationFactory::class); } diff --git a/Classes/Dispatcher/HeadlessDispatcher.php b/Classes/Dispatcher/HeadlessDispatcher.php index 9b7562e..35377e1 100644 --- a/Classes/Dispatcher/HeadlessDispatcher.php +++ b/Classes/Dispatcher/HeadlessDispatcher.php @@ -8,5 +8,8 @@ class HeadlessDispatcher extends AbstractDispatcher implements SingletonInterface { - // @TODO This comment is here just for reformatting compatibility of csfixes and phpstorm. + protected function init(): void + { + // @TODO This comment is here just for reformatting compatibility of csfixes and phpstorm. + } } diff --git a/Classes/Domain/Repository/ApiResourceRepository.php b/Classes/Domain/Repository/ApiResourceRepository.php index 40ec8ec..da7288f 100644 --- a/Classes/Domain/Repository/ApiResourceRepository.php +++ b/Classes/Domain/Repository/ApiResourceRepository.php @@ -4,9 +4,9 @@ namespace SourceBroker\T3api\Domain\Repository; -use SourceBroker\T3api\Configuration\Configuration; use SourceBroker\T3api\Domain\Model\ApiResource; use SourceBroker\T3api\Factory\ApiResourceFactory; +use SourceBroker\T3api\Factory\ApiResourcePathProviderCollectionFactory; use SourceBroker\T3api\Service\ReflectionService; use SourceBroker\T3api\Service\RouteService; use TYPO3\CMS\Core\Cache\CacheManager; @@ -20,7 +20,8 @@ class ApiResourceRepository public function __construct( protected readonly CacheManager $cacheManager, protected readonly ReflectionService $reflectionService, - protected readonly ApiResourceFactory $apiResourceFactory + protected readonly ApiResourceFactory $apiResourceFactory, + protected readonly ApiResourcePathProviderCollectionFactory $apiResourcePathProviderCollectionFactory ) { $this->cache = $cacheManager->getCache('t3api'); } @@ -81,7 +82,7 @@ protected function getAllDomainModels(): iterable */ protected function getAllDomainModelClassNames(): iterable { - foreach (Configuration::getApiResourcePathProviders() as $apiResourcePathProvider) { + foreach ($this->apiResourcePathProviderCollectionFactory->get() as $apiResourcePathProvider) { foreach ($apiResourcePathProvider->getAll() as $domainModelClassFile) { $className = $this->reflectionService->getClassNameFromFile($domainModelClassFile); if ($className !== null && $className !== '') { diff --git a/Classes/Factory/ApiResourcePathProviderCollectionFactory.php b/Classes/Factory/ApiResourcePathProviderCollectionFactory.php new file mode 100644 index 0000000..285359f --- /dev/null +++ b/Classes/Factory/ApiResourcePathProviderCollectionFactory.php @@ -0,0 +1,39 @@ +apiResourcePathProviders as $apiResourcePathProvider) { + if (!$apiResourcePathProvider instanceof ApiResourcePathProvider) { + throw new \InvalidArgumentException( + sprintf( + 'API resource path provider `%s` has to be an instance of `%s`', + $apiResourcePathProvider::class, + ApiResourcePathProvider::class + ), + 1609066405400 + ); + } + + yield $apiResourcePathProvider; + } + + foreach (Configuration::getApiResourcePathProviders() as $apiResourcePathProvider) { + yield $apiResourcePathProvider; + } + } +} diff --git a/Classes/Factory/GetMergedTrait.php b/Classes/Factory/GetMergedTrait.php new file mode 100644 index 0000000..1388541 --- /dev/null +++ b/Classes/Factory/GetMergedTrait.php @@ -0,0 +1,21 @@ + GeneralUtility::makeInstance($className), + $names + ) + ); + } +} diff --git a/Classes/Factory/OperationHandlerCollectionFactory.php b/Classes/Factory/OperationHandlerCollectionFactory.php new file mode 100644 index 0000000..ca499a9 --- /dev/null +++ b/Classes/Factory/OperationHandlerCollectionFactory.php @@ -0,0 +1,23 @@ +getInstances($this->operationHandlers, Configuration::getOperationHandlers()); + } +} diff --git a/Classes/Factory/ProcessorsCollectionFactory.php b/Classes/Factory/ProcessorsCollectionFactory.php new file mode 100644 index 0000000..8b52ace --- /dev/null +++ b/Classes/Factory/ProcessorsCollectionFactory.php @@ -0,0 +1,23 @@ +getInstances($this->processors, Configuration::getProcessors()); + } +} diff --git a/Classes/Factory/SerializerHandlerCollectionFactory.php b/Classes/Factory/SerializerHandlerCollectionFactory.php new file mode 100644 index 0000000..3cfd633 --- /dev/null +++ b/Classes/Factory/SerializerHandlerCollectionFactory.php @@ -0,0 +1,23 @@ +getInstances($this->serializerHandlers, Configuration::getSerializerHandlers()); + } +} diff --git a/Classes/Factory/SerializerObjectConstructorCollection.php b/Classes/Factory/SerializerObjectConstructorCollection.php new file mode 100644 index 0000000..cacf13f --- /dev/null +++ b/Classes/Factory/SerializerObjectConstructorCollection.php @@ -0,0 +1,23 @@ +getInstances($this->constructorsInstances, Configuration::getSerializerObjectConstructors()); + } +} diff --git a/Classes/Factory/SerializerSubscriberCollectionFactory.php b/Classes/Factory/SerializerSubscriberCollectionFactory.php new file mode 100644 index 0000000..b8bb1df --- /dev/null +++ b/Classes/Factory/SerializerSubscriberCollectionFactory.php @@ -0,0 +1,23 @@ +getInstances($this->serializerSubscribers, Configuration::getSerializerSubscribers()); + } +} diff --git a/Classes/OperationHandler/CollectionGetOperationHandler.php b/Classes/OperationHandler/CollectionGetOperationHandler.php index ce7b010..9fdcbff 100644 --- a/Classes/OperationHandler/CollectionGetOperationHandler.php +++ b/Classes/OperationHandler/CollectionGetOperationHandler.php @@ -5,6 +5,7 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Configuration\Configuration; use SourceBroker\T3api\Domain\Model\CollectionOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; @@ -12,6 +13,7 @@ use Symfony\Component\HttpFoundation\Request; use TYPO3\CMS\Core\Utility\GeneralUtility; +#[AsOperationHandler(priority: -500)] class CollectionGetOperationHandler extends AbstractCollectionOperationHandler { public static function supports(OperationInterface $operation, Request $request): bool diff --git a/Classes/OperationHandler/CollectionMethodNotAllowedOperationHandler.php b/Classes/OperationHandler/CollectionMethodNotAllowedOperationHandler.php index 7644109..c8f052e 100644 --- a/Classes/OperationHandler/CollectionMethodNotAllowedOperationHandler.php +++ b/Classes/OperationHandler/CollectionMethodNotAllowedOperationHandler.php @@ -5,10 +5,12 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\MethodNotAllowedException; use Symfony\Component\HttpFoundation\Request; +#[AsOperationHandler(priority: -9999)] class CollectionMethodNotAllowedOperationHandler extends AbstractItemOperationHandler { /** diff --git a/Classes/OperationHandler/CollectionPostOperationHandler.php b/Classes/OperationHandler/CollectionPostOperationHandler.php index 675e805..78a6a90 100644 --- a/Classes/OperationHandler/CollectionPostOperationHandler.php +++ b/Classes/OperationHandler/CollectionPostOperationHandler.php @@ -5,6 +5,7 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\CollectionOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\OperationNotAllowedException; @@ -14,6 +15,7 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +#[AsOperationHandler(priority: -500)] class CollectionPostOperationHandler extends AbstractCollectionOperationHandler { public static function supports(OperationInterface $operation, Request $request): bool diff --git a/Classes/OperationHandler/FileUploadOperationHandler.php b/Classes/OperationHandler/FileUploadOperationHandler.php index 2e5f3bd..a77b202 100644 --- a/Classes/OperationHandler/FileUploadOperationHandler.php +++ b/Classes/OperationHandler/FileUploadOperationHandler.php @@ -6,6 +6,7 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\CollectionOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\OperationNotAllowedException; @@ -18,6 +19,7 @@ use TYPO3\CMS\Core\Resource\Exception; use TYPO3\CMS\Extbase\Domain\Model\File; +#[AsOperationHandler(priority: -400)] class FileUploadOperationHandler extends AbstractCollectionOperationHandler { protected FileUploadService $fileUploadService; diff --git a/Classes/OperationHandler/ItemDeleteOperationHandler.php b/Classes/OperationHandler/ItemDeleteOperationHandler.php index 1ae88b8..cee65b3 100644 --- a/Classes/OperationHandler/ItemDeleteOperationHandler.php +++ b/Classes/OperationHandler/ItemDeleteOperationHandler.php @@ -5,6 +5,7 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\ItemOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\OperationNotAllowedException; @@ -13,6 +14,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +#[AsOperationHandler(priority: -500)] class ItemDeleteOperationHandler extends AbstractItemOperationHandler { public static function supports(OperationInterface $operation, Request $request): bool diff --git a/Classes/OperationHandler/ItemGetOperationHandler.php b/Classes/OperationHandler/ItemGetOperationHandler.php index b8bde91..40a8c47 100644 --- a/Classes/OperationHandler/ItemGetOperationHandler.php +++ b/Classes/OperationHandler/ItemGetOperationHandler.php @@ -5,6 +5,7 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\ItemOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\OperationNotAllowedException; @@ -12,6 +13,7 @@ use Symfony\Component\HttpFoundation\Request; use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; +#[AsOperationHandler(priority: -500)] class ItemGetOperationHandler extends AbstractItemOperationHandler { public static function supports(OperationInterface $operation, Request $request): bool diff --git a/Classes/OperationHandler/ItemMethodNotAllowedOperationHandler.php b/Classes/OperationHandler/ItemMethodNotAllowedOperationHandler.php index 1235a49..5029f44 100644 --- a/Classes/OperationHandler/ItemMethodNotAllowedOperationHandler.php +++ b/Classes/OperationHandler/ItemMethodNotAllowedOperationHandler.php @@ -5,10 +5,12 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\MethodNotAllowedException; use Symfony\Component\HttpFoundation\Request; +#[AsOperationHandler(priority: -9999)] class ItemMethodNotAllowedOperationHandler extends AbstractItemOperationHandler { /** diff --git a/Classes/OperationHandler/ItemPatchOperationHandler.php b/Classes/OperationHandler/ItemPatchOperationHandler.php index 15ff473..47d696f 100644 --- a/Classes/OperationHandler/ItemPatchOperationHandler.php +++ b/Classes/OperationHandler/ItemPatchOperationHandler.php @@ -5,6 +5,7 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\ItemOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\OperationNotAllowedException; @@ -16,6 +17,7 @@ use TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +#[AsOperationHandler(priority: -500)] class ItemPatchOperationHandler extends AbstractItemOperationHandler { public static function supports(OperationInterface $operation, Request $request): bool diff --git a/Classes/OperationHandler/ItemPutOperationHandler.php b/Classes/OperationHandler/ItemPutOperationHandler.php index 1c85d7b..d181e3b 100644 --- a/Classes/OperationHandler/ItemPutOperationHandler.php +++ b/Classes/OperationHandler/ItemPutOperationHandler.php @@ -5,6 +5,7 @@ namespace SourceBroker\T3api\OperationHandler; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\ItemOperation; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Exception\OperationNotAllowedException; @@ -15,6 +16,7 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +#[AsOperationHandler(priority: -500)] class ItemPutOperationHandler extends AbstractItemOperationHandler { public static function supports(OperationInterface $operation, Request $request): bool diff --git a/Classes/OperationHandler/OptionsOperationHandler.php b/Classes/OperationHandler/OptionsOperationHandler.php index 845a181..ceef282 100644 --- a/Classes/OperationHandler/OptionsOperationHandler.php +++ b/Classes/OperationHandler/OptionsOperationHandler.php @@ -4,6 +4,7 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsOperationHandler; use SourceBroker\T3api\Domain\Model\OperationInterface; use SourceBroker\T3api\Security\OperationAccessChecker; use SourceBroker\T3api\Serializer\ContextBuilder\DeserializationContextBuilder; @@ -13,6 +14,7 @@ use Symfony\Component\HttpFoundation\Request; use TYPO3\CMS\Core\Http\Response; +#[AsOperationHandler(priority: 10500)] class OptionsOperationHandler extends AbstractOperationHandler { private ?CorsService $corsService; diff --git a/Classes/Processor/CorsProcessor.php b/Classes/Processor/CorsProcessor.php index 51bed4f..21f2896 100644 --- a/Classes/Processor/CorsProcessor.php +++ b/Classes/Processor/CorsProcessor.php @@ -5,9 +5,11 @@ namespace SourceBroker\T3api\Processor; use Psr\Http\Message\ResponseInterface; +use SourceBroker\T3api\Attribute\AsProcessor; use SourceBroker\T3api\Service\CorsService; use Symfony\Component\HttpFoundation\Request; +#[AsProcessor(priority: 100)] class CorsProcessor implements ProcessorInterface { public function __construct(private readonly ?CorsService $corsService) {} diff --git a/Classes/Provider/ApiResourcePath/LoadedExtensionsDomainModelApiResourcePathProvider.php b/Classes/Provider/ApiResourcePath/LoadedExtensionsDomainModelApiResourcePathProvider.php index 0331b6f..0b49ca2 100644 --- a/Classes/Provider/ApiResourcePath/LoadedExtensionsDomainModelApiResourcePathProvider.php +++ b/Classes/Provider/ApiResourcePath/LoadedExtensionsDomainModelApiResourcePathProvider.php @@ -4,9 +4,11 @@ namespace SourceBroker\T3api\Provider\ApiResourcePath; +use SourceBroker\T3api\Attribute\AsApiResourcePathProvider; use SourceBroker\T3api\Utility\FileUtility; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; +#[AsApiResourcePathProvider] class LoadedExtensionsDomainModelApiResourcePathProvider implements ApiResourcePathProvider { public function getAll(): iterable diff --git a/Classes/Serializer/Construction/ExtbaseObjectConstructor.php b/Classes/Serializer/Construction/ExtbaseObjectConstructor.php index eefd5be..be6ed7e 100644 --- a/Classes/Serializer/Construction/ExtbaseObjectConstructor.php +++ b/Classes/Serializer/Construction/ExtbaseObjectConstructor.php @@ -8,8 +8,10 @@ use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Visitor\DeserializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerObjectConstructor; use TYPO3\CMS\Core\Utility\GeneralUtility; +#[AsSerializerObjectConstructor(priority: 400)] class ExtbaseObjectConstructor implements ObjectConstructorInterface { /** diff --git a/Classes/Serializer/Construction/InitializedObjectConstructor.php b/Classes/Serializer/Construction/InitializedObjectConstructor.php index ad84150..9763856 100644 --- a/Classes/Serializer/Construction/InitializedObjectConstructor.php +++ b/Classes/Serializer/Construction/InitializedObjectConstructor.php @@ -8,11 +8,13 @@ use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Visitor\DeserializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerObjectConstructor; /** * Object constructor that allows deserialization into already constructed * objects passed through the deserialization context */ +#[AsSerializerObjectConstructor(priority: 500)] class InitializedObjectConstructor implements ObjectConstructorInterface { /** diff --git a/Classes/Serializer/Construction/ObjectConstructorChain.php b/Classes/Serializer/Construction/ObjectConstructorChain.php index e8a2bca..82af298 100644 --- a/Classes/Serializer/Construction/ObjectConstructorChain.php +++ b/Classes/Serializer/Construction/ObjectConstructorChain.php @@ -8,27 +8,11 @@ use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Visitor\DeserializationVisitorInterface; -use TYPO3\CMS\Core\Utility\GeneralUtility; +use SourceBroker\T3api\Factory\SerializerObjectConstructorCollection; class ObjectConstructorChain implements ObjectConstructorInterface { - /** - * @var string[] - */ - protected $constructors = []; - - /** - * @var ObjectConstructorInterface[]|null - */ - protected $constructorsInstances; - - /** - * @param string[] $constructors - */ - public function __construct($constructors) - { - $this->constructors = $constructors; - } + public function __construct(protected SerializerObjectConstructorCollection $serializerObjectConstructorCollection) {} /** * @inheritDoc @@ -40,7 +24,7 @@ public function construct( array $type, DeserializationContext $context ): ?object { - foreach ($this->getConstructorsInstances() as $constructor) { + foreach ($this->serializerObjectConstructorCollection->get() as $constructor) { $object = $constructor->construct($visitor, $metadata, $data, $type, $context); if ($object !== null) { @@ -50,19 +34,4 @@ public function construct( throw new \RuntimeException(sprintf('Could not construct object `%s`', $metadata->name), 1577822761813); } - - /** - * @return ObjectConstructorInterface[] - */ - protected function getConstructorsInstances(): array - { - if ($this->constructorsInstances === null) { - $this->constructorsInstances = []; - foreach ($this->constructors as $constructor) { - $this->constructorsInstances[] = GeneralUtility::makeInstance($constructor); - } - } - - return $this->constructorsInstances; - } } diff --git a/Classes/Serializer/Handler/AbstractDomainObjectHandler.php b/Classes/Serializer/Handler/AbstractDomainObjectHandler.php index b71cf55..9ed5dc8 100644 --- a/Classes/Serializer/Handler/AbstractDomainObjectHandler.php +++ b/Classes/Serializer/Handler/AbstractDomainObjectHandler.php @@ -8,6 +8,7 @@ use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use SourceBroker\T3api\Annotation\ORM\Cascade; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use SourceBroker\T3api\Service\PropertyInfoService; use SourceBroker\T3api\Service\SerializerService; use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; @@ -15,6 +16,7 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage; use TYPO3\CMS\Extbase\Reflection\ObjectAccess; +#[AsSerializerHandler] class AbstractDomainObjectHandler extends AbstractHandler implements DeserializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/CurrentFeUserHandler.php b/Classes/Serializer/Handler/CurrentFeUserHandler.php index f69e214..f780eef 100644 --- a/Classes/Serializer/Handler/CurrentFeUserHandler.php +++ b/Classes/Serializer/Handler/CurrentFeUserHandler.php @@ -6,9 +6,11 @@ use JMS\Serializer\DeserializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; +#[AsSerializerHandler] class CurrentFeUserHandler extends AbstractHandler implements DeserializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/FileReferenceHandler.php b/Classes/Serializer/Handler/FileReferenceHandler.php index 5772b9a..9dbcf3d 100644 --- a/Classes/Serializer/Handler/FileReferenceHandler.php +++ b/Classes/Serializer/Handler/FileReferenceHandler.php @@ -9,6 +9,7 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use SourceBroker\T3api\Exception\ValidationException; use SourceBroker\T3api\Service\FileReferenceService; use SourceBroker\T3api\Service\SerializerService; @@ -26,6 +27,7 @@ use TYPO3\CMS\Extbase\Reflection\ObjectAccess; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +#[AsSerializerHandler] class FileReferenceHandler extends AbstractHandler implements SerializeHandlerInterface, DeserializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/ImageHandler.php b/Classes/Serializer/Handler/ImageHandler.php index 069d2dc..c66a5eb 100644 --- a/Classes/Serializer/Handler/ImageHandler.php +++ b/Classes/Serializer/Handler/ImageHandler.php @@ -6,6 +6,7 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use SourceBroker\T3api\Service\FileReferenceService; use TYPO3\CMS\Core\Imaging\ImageManipulation\Area; use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection; @@ -14,6 +15,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Domain\Model\FileReference; +#[AsSerializerHandler] class ImageHandler extends AbstractHandler implements SerializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/ObjectStorageHandler.php b/Classes/Serializer/Handler/ObjectStorageHandler.php index 2ff9031..625561f 100644 --- a/Classes/Serializer/Handler/ObjectStorageHandler.php +++ b/Classes/Serializer/Handler/ObjectStorageHandler.php @@ -8,9 +8,11 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage; use TYPO3\CMS\Extbase\Persistence\ObjectStorage; +#[AsSerializerHandler] class ObjectStorageHandler extends AbstractHandler implements SerializeHandlerInterface, DeserializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/PasswordHashHandler.php b/Classes/Serializer/Handler/PasswordHashHandler.php index 3813115..672a2bb 100644 --- a/Classes/Serializer/Handler/PasswordHashHandler.php +++ b/Classes/Serializer/Handler/PasswordHashHandler.php @@ -8,8 +8,10 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory; +#[AsSerializerHandler] class PasswordHashHandler extends AbstractHandler implements SerializeHandlerInterface, DeserializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/RecordUriHandler.php b/Classes/Serializer/Handler/RecordUriHandler.php index 8038834..f8844d7 100644 --- a/Classes/Serializer/Handler/RecordUriHandler.php +++ b/Classes/Serializer/Handler/RecordUriHandler.php @@ -6,10 +6,12 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use SourceBroker\T3api\Service\UrlService; use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +#[AsSerializerHandler] class RecordUriHandler extends AbstractHandler implements SerializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/RteHandler.php b/Classes/Serializer/Handler/RteHandler.php index ff9dcaf..d7cc9da 100644 --- a/Classes/Serializer/Handler/RteHandler.php +++ b/Classes/Serializer/Handler/RteHandler.php @@ -6,9 +6,11 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +#[AsSerializerHandler] class RteHandler extends AbstractHandler implements SerializeHandlerInterface { /** diff --git a/Classes/Serializer/Handler/TypolinkHandler.php b/Classes/Serializer/Handler/TypolinkHandler.php index 8cb132a..a4e4c56 100644 --- a/Classes/Serializer/Handler/TypolinkHandler.php +++ b/Classes/Serializer/Handler/TypolinkHandler.php @@ -6,9 +6,11 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use SourceBroker\T3api\Attribute\AsSerializerHandler; use SourceBroker\T3api\Service\UrlService; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +#[AsSerializerHandler] class TypolinkHandler extends AbstractHandler implements SerializeHandlerInterface { /** diff --git a/Classes/Serializer/Subscriber/AbstractEntitySubscriber.php b/Classes/Serializer/Subscriber/AbstractEntitySubscriber.php index ab530c1..dedef6d 100644 --- a/Classes/Serializer/Subscriber/AbstractEntitySubscriber.php +++ b/Classes/Serializer/Subscriber/AbstractEntitySubscriber.php @@ -10,6 +10,7 @@ use JMS\Serializer\EventDispatcher\PreDeserializeEvent; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Metadata\StaticPropertyMetadata; +use SourceBroker\T3api\Attribute\AsSerializerSubscriber; use SourceBroker\T3api\Domain\Model\ApiResource; use SourceBroker\T3api\Domain\Model\ItemOperation; use SourceBroker\T3api\Domain\Repository\ApiResourceRepository; @@ -17,6 +18,7 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; use TYPO3\CMS\Extbase\Reflection\ObjectAccess; +#[AsSerializerSubscriber] class AbstractEntitySubscriber implements EventSubscriberInterface { public function __construct(protected readonly ApiResourceRepository $apiResourceRepository) {} diff --git a/Classes/Serializer/Subscriber/CurrentFeUserSubscriber.php b/Classes/Serializer/Subscriber/CurrentFeUserSubscriber.php index 7e82968..2ab568c 100644 --- a/Classes/Serializer/Subscriber/CurrentFeUserSubscriber.php +++ b/Classes/Serializer/Subscriber/CurrentFeUserSubscriber.php @@ -11,8 +11,10 @@ use Metadata\ClassHierarchyMetadata; use Metadata\ClassMetadata; use Metadata\MergeableClassMetadata; +use SourceBroker\T3api\Attribute\AsSerializerSubscriber; use SourceBroker\T3api\Serializer\Handler\CurrentFeUserHandler; +#[AsSerializerSubscriber] class CurrentFeUserSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array diff --git a/Classes/Serializer/Subscriber/FileReferenceSubscriber.php b/Classes/Serializer/Subscriber/FileReferenceSubscriber.php index 5e6e8cf..e0df7cb 100644 --- a/Classes/Serializer/Subscriber/FileReferenceSubscriber.php +++ b/Classes/Serializer/Subscriber/FileReferenceSubscriber.php @@ -9,10 +9,12 @@ use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\PreDeserializeEvent; use JMS\Serializer\EventDispatcher\PreSerializeEvent; +use SourceBroker\T3api\Attribute\AsSerializerSubscriber; use SourceBroker\T3api\Domain\Repository\ApiResourceRepository; use SourceBroker\T3api\Serializer\Handler\FileReferenceHandler; use TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder; +#[AsSerializerSubscriber] class FileReferenceSubscriber implements EventSubscriberInterface { public function __construct(protected readonly ApiResourceRepository $apiResourceRepository) {} diff --git a/Classes/Serializer/Subscriber/GenerateMetadataSubscriber.php b/Classes/Serializer/Subscriber/GenerateMetadataSubscriber.php index 37693cf..b236faf 100644 --- a/Classes/Serializer/Subscriber/GenerateMetadataSubscriber.php +++ b/Classes/Serializer/Subscriber/GenerateMetadataSubscriber.php @@ -8,8 +8,10 @@ use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; use JMS\Serializer\EventDispatcher\PreDeserializeEvent; +use SourceBroker\T3api\Attribute\AsSerializerSubscriber; use SourceBroker\T3api\Service\SerializerMetadataService; +#[AsSerializerSubscriber] class GenerateMetadataSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array diff --git a/Classes/Serializer/Subscriber/ThrowableSubscriber.php b/Classes/Serializer/Subscriber/ThrowableSubscriber.php index 038990b..8ad2d24 100644 --- a/Classes/Serializer/Subscriber/ThrowableSubscriber.php +++ b/Classes/Serializer/Subscriber/ThrowableSubscriber.php @@ -9,8 +9,10 @@ use JMS\Serializer\EventDispatcher\ObjectEvent; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Metadata\StaticPropertyMetadata; +use SourceBroker\T3api\Attribute\AsSerializerSubscriber; use SourceBroker\T3api\Service\SerializerService; +#[AsSerializerSubscriber] class ThrowableSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array diff --git a/Classes/Service/SerializerService.php b/Classes/Service/SerializerService.php index f1858e6..1ced13a 100644 --- a/Classes/Service/SerializerService.php +++ b/Classes/Service/SerializerService.php @@ -24,6 +24,8 @@ use Metadata\Cache\FileCache; use Metadata\MetadataFactory; use Metadata\MetadataFactoryInterface; +use SourceBroker\T3api\Factory\SerializerHandlerCollectionFactory; +use SourceBroker\T3api\Factory\SerializerSubscriberCollectionFactory; use SourceBroker\T3api\Serializer\Accessor\AccessorStrategy; use SourceBroker\T3api\Serializer\Construction\ObjectConstructorChain; use SourceBroker\T3api\Serializer\ContextBuilder\DeserializationContextBuilder; @@ -38,7 +40,9 @@ class SerializerService implements SingletonInterface { public function __construct( protected readonly SerializationContextBuilder $serializationContextBuilder, - protected readonly DeserializationContextBuilder $deserializationContextBuilder + protected readonly DeserializationContextBuilder $deserializationContextBuilder, + protected readonly SerializerHandlerCollectionFactory $serializerHandlerCollectionFactory, + protected readonly SerializerSubscriberCollectionFactory $serializerSubscriberCollectionFactory ) {} public static function getSerializerCacheDirectory(): string @@ -106,21 +110,23 @@ public function getSerializerBuilder(): SerializerBuilder static $serializerBuilder; if (empty($serializerBuilder)) { + $serializerHandlers = $this->serializerHandlerCollectionFactory->get(); + $serializerSubscribers = $this->serializerSubscriberCollectionFactory->get(); $serializerBuilder = SerializerBuilder::create() ->setCacheDir(self::getSerializerCacheDirectory()) ->setDebug(self::isDebugMode()) - ->configureHandlers(static function (HandlerRegistry $registry): void { - foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerHandlers'] ?? [] as $handlerClass) { - /** @var SubscribingHandlerInterface $handler */ - $handler = GeneralUtility::makeInstance($handlerClass); - $registry->registerSubscribingHandler($handler); + ->configureHandlers(static function (HandlerRegistry $registry) use ($serializerHandlers): void { + foreach ($serializerHandlers as $handler) { + if ($handler instanceof SubscribingHandlerInterface) { + $registry->registerSubscribingHandler($handler); + } } }) - ->configureListeners(static function (EventDispatcher $dispatcher): void { - foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerSubscribers'] ?? [] as $subscriberClass) { - /** @var EventSubscriberInterface $subscriber */ - $subscriber = GeneralUtility::makeInstance($subscriberClass); - $dispatcher->addSubscriber($subscriber); + ->configureListeners(static function (EventDispatcher $dispatcher) use ($serializerSubscribers): void { + foreach ($serializerSubscribers as $subscriber) { + if ($subscriber instanceof EventSubscriberInterface) { + $dispatcher->addSubscriber($subscriber); + } } }) ->addDefaultHandlers() @@ -130,10 +136,7 @@ public function getSerializerBuilder(): SerializerBuilder ->setMetadataDriverFactory($this->getDriverFactory()) ->setMetadataCache(self::getMetadataCache()) ->addMetadataDirs(self::getMetadataDirs()) - ->setObjectConstructor(GeneralUtility::makeInstance( - ObjectConstructorChain::class, - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerObjectConstructors'] - )) + ->setObjectConstructor(GeneralUtility::makeInstance(ObjectConstructorChain::class)) ->setExpressionEvaluator(self::getExpressionEvaluator()); } diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 4a272ee..82be2c6 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -21,99 +21,22 @@ services: SourceBroker\T3api\Response\MainEndpointResponse: public: true - SourceBroker\T3api\OperationHandler\CollectionGetOperationHandler: - public: true - SourceBroker\T3api\Domain\Repository\CommonRepository: public: true - SourceBroker\T3api\OperationHandler\OptionsOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\FileUploadOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\CollectionPostOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\CollectionMethodNotAllowedOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\ItemGetOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\ItemPutOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\ItemPatchOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\ItemDeleteOperationHandler: - public: true - - SourceBroker\T3api\OperationHandler\ItemMethodNotAllowedOperationHandler: - public: true - - SourceBroker\T3api\Processor\CorsProcessor: - public: true - SourceBroker\T3api\Processor\LanguageProcessor: public: true - SourceBroker\T3api\Provider\ApiResourcePath\LoadedExtensionsDomainModelApiResourcePathProvider: - public: true - - SourceBroker\T3api\Serializer\Construction\InitializedObjectConstructor: - public: true - - SourceBroker\T3api\Serializer\Construction\ExtbaseObjectConstructor: - public: true - - SourceBroker\T3api\Serializer\Handler\AbstractDomainObjectHandler: - public: true - - SourceBroker\T3api\Serializer\Handler\ObjectStorageHandler: - public: true - - SourceBroker\T3api\Serializer\Handler\FileReferenceHandler: - public: true - - SourceBroker\T3api\Serializer\Handler\ImageHandler: + SourceBroker\T3api\Serializer\Construction\ObjectConstructorChain: public: true SourceBroker\T3api\Serializer\Handler\RecordUriHandler: arguments: $contentObjectRenderer: '@TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer' - public: true SourceBroker\T3api\Serializer\Handler\TypolinkHandler: arguments: $contentObjectRenderer: '@TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer' - public: true - - SourceBroker\T3api\Serializer\Handler\CurrentFeUserHandler: - public: true - - SourceBroker\T3api\Serializer\Handler\RteHandler: - public: true - - SourceBroker\T3api\Serializer\Handler\PasswordHashHandler: - public: true - - SourceBroker\T3api\Serializer\Subscriber\GenerateMetadataSubscriber: - public: true - - SourceBroker\T3api\Serializer\Subscriber\FileReferenceSubscriber: - public: true - - SourceBroker\T3api\Serializer\Subscriber\AbstractEntitySubscriber: - public: true - - SourceBroker\T3api\Serializer\Subscriber\ThrowableSubscriber: - public: true - - SourceBroker\T3api\Serializer\Subscriber\CurrentFeUserSubscriber: - public: true SourceBroker\T3api\Response\HydraCollectionResponse: public: true diff --git a/Tests/Functional/Domain/Repository/ApiResourceRepositoryTest.php b/Tests/Functional/Domain/Repository/ApiResourceRepositoryTest.php index 6585a91..17740ba 100644 --- a/Tests/Functional/Domain/Repository/ApiResourceRepositoryTest.php +++ b/Tests/Functional/Domain/Repository/ApiResourceRepositoryTest.php @@ -6,6 +6,7 @@ use SourceBroker\T3api\Domain\Repository\ApiResourceRepository; use SourceBroker\T3api\Factory\ApiResourceFactory; +use SourceBroker\T3api\Factory\ApiResourcePathProviderCollectionFactory; use SourceBroker\T3api\Service\ReflectionService; use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; @@ -15,6 +16,7 @@ class ApiResourceRepositoryTest extends FunctionalTestCase protected array $testExtensionsToLoad = ['typo3conf/ext/t3api']; protected CacheManager $cacheManager; protected ApiResourceFactory $apiResourceFactory; + protected ApiResourcePathProviderCollectionFactory $apiResourcePathProviderCollectionFactory; protected ReflectionService $reflectionService; public function setUp(): void @@ -23,6 +25,7 @@ public function setUp(): void $this->cacheManager = $this->getMockBuilder(CacheManager::class)->disableOriginalConstructor()->getMock(); $this->reflectionService = $this->getMockBuilder(ReflectionService::class)->disableOriginalConstructor()->getMock(); $this->apiResourceFactory = $this->getMockBuilder(ApiResourceFactory::class)->disableOriginalConstructor()->getMock(); + $this->apiResourcePathProviderCollectionFactory = $this->getMockBuilder(ApiResourcePathProviderCollectionFactory::class)->disableOriginalConstructor()->getMock(); } /** @@ -35,7 +38,8 @@ public function getAllDomainModelsReturnsAllClasses(): void $apiResourceRepository = new ApiResourceRepository( $this->cacheManager, $this->reflectionService, - $this->apiResourceFactory + $this->apiResourceFactory, + $this->apiResourcePathProviderCollectionFactory ); // iterator_to_arrays converts the Generator object to an array because Generator can not be serialized diff --git a/ext_localconf.php b/ext_localconf.php index c107236..33ccfa4 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -8,52 +8,6 @@ static function () { $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['basePath'] = '_api'; $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['languageHeader'] = 'X-Locale'; - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['operationHandlers'] = [ - \SourceBroker\T3api\OperationHandler\OptionsOperationHandler::class => 10500, - \SourceBroker\T3api\OperationHandler\FileUploadOperationHandler::class => -400, - \SourceBroker\T3api\OperationHandler\CollectionGetOperationHandler::class => -500, - \SourceBroker\T3api\OperationHandler\CollectionPostOperationHandler::class => -500, - \SourceBroker\T3api\OperationHandler\CollectionMethodNotAllowedOperationHandler::class => -9999, - \SourceBroker\T3api\OperationHandler\ItemGetOperationHandler::class => -500, - \SourceBroker\T3api\OperationHandler\ItemPutOperationHandler::class => -500, - \SourceBroker\T3api\OperationHandler\ItemPatchOperationHandler::class => -500, - \SourceBroker\T3api\OperationHandler\ItemDeleteOperationHandler::class => -500, - \SourceBroker\T3api\OperationHandler\ItemMethodNotAllowedOperationHandler::class => -9999, - ]; - - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['processors'] = [ - \SourceBroker\T3api\Processor\CorsProcessor::class => 100, - ]; - - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['apiResourcePathProviders'] = [ - \SourceBroker\T3api\Provider\ApiResourcePath\LoadedExtensionsDomainModelApiResourcePathProvider::class, - ]; - - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerObjectConstructors'] = [ - \SourceBroker\T3api\Serializer\Construction\InitializedObjectConstructor::class, - \SourceBroker\T3api\Serializer\Construction\ExtbaseObjectConstructor::class, - ]; - - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerHandlers'] = [ - \SourceBroker\T3api\Serializer\Handler\AbstractDomainObjectHandler::class, - \SourceBroker\T3api\Serializer\Handler\ObjectStorageHandler::class, - \SourceBroker\T3api\Serializer\Handler\FileReferenceHandler::class, - \SourceBroker\T3api\Serializer\Handler\ImageHandler::class, - \SourceBroker\T3api\Serializer\Handler\RecordUriHandler::class, - \SourceBroker\T3api\Serializer\Handler\TypolinkHandler::class, - \SourceBroker\T3api\Serializer\Handler\CurrentFeUserHandler::class, - \SourceBroker\T3api\Serializer\Handler\RteHandler::class, - \SourceBroker\T3api\Serializer\Handler\PasswordHashHandler::class, - ]; - - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerSubscribers'] = [ - \SourceBroker\T3api\Serializer\Subscriber\GenerateMetadataSubscriber::class, - \SourceBroker\T3api\Serializer\Subscriber\FileReferenceSubscriber::class, - \SourceBroker\T3api\Serializer\Subscriber\AbstractEntitySubscriber::class, - \SourceBroker\T3api\Serializer\Subscriber\ThrowableSubscriber::class, - \SourceBroker\T3api\Serializer\Subscriber\CurrentFeUserSubscriber::class, - ]; - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3api']['serializerMetadataDirs'] = [ 't3api' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('t3api') . 'Resources/Private/Serializer/Metadata', ];