diff --git a/composer.json b/composer.json index aa46df9bc..27b78ad4c 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "require": { "php": "~8.1.0 || ~8.2.0", "pimcore/enterprise-subscription-tools": "^1.3", + "pimcore/static-website": "^1.0", "pimcore/pimcore": "^11.0", "api-platform/core": "^3.2" }, diff --git a/config/api_platform/resources/asset.yaml b/config/api_platform/resources/asset.yaml index 77d1edbd4..fb2a8fd30 100644 --- a/config/api_platform/resources/asset.yaml +++ b/config/api_platform/resources/asset.yaml @@ -1,31 +1,26 @@ resources: - Pimcore\Model\Asset: + Pimcore\Bundle\StudioApiBundle\Dto\Asset: + operations: + ApiPlatform\Metadata\GetCollection: + filters: [ Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter ] + paginationClientItemsPerPage: true + ApiPlatform\Metadata\Get: + normalizationContext: + groups: [ 'asset:read', 'asset:item:get', 'dependency:read', 'property:read'] + ApiPlatform\Metadata\Put: + ApiPlatform\Metadata\Post: + ApiPlatform\Metadata\Delete: + ApiPlatform\Metadata\Patch: provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider normalizationContext: - groups: ['get'] + groups: ['asset:read', 'dependency:read', 'property:read'] denormalizationContext: - groups: ['set'] + groups: ['asset:write'] properties: id: identifier: true - parentId: ~ - type: ~ - data: ~ - fullPath: ~ - Pimcore\Model\Asset\Image: - provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider - properties: - id: - identifier: true - normalizationContext: - groups: ['get'] - denormalizationContext: - groups: ['set'] - - Pimcore\Model\Asset\Image\Thumbnail: - provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider - normalizationContext: - groups: ['get'] - denormalizationContext: - groups: ['set'] +properties: + Pimcore\Bundle\StudioApiBundle\Dto\Asset: + dependencies: + genId: false \ No newline at end of file diff --git a/config/api_platform/resources/asset/image.yaml b/config/api_platform/resources/asset/image.yaml new file mode 100644 index 000000000..c2763f008 --- /dev/null +++ b/config/api_platform/resources/asset/image.yaml @@ -0,0 +1,10 @@ +resources: + Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image: + provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider + properties: + id: + identifier: true + normalizationContext: + groups: ['image:read', 'asset:read', 'task:read', 'dependency:read', 'property:read', 'version:read'] + denormalizationContext: + groups: ['image:write', 'asset:write'] \ No newline at end of file diff --git a/config/api_platform/resources/schedule/task.yaml b/config/api_platform/resources/schedule/task.yaml new file mode 100644 index 000000000..6f6f2ecd0 --- /dev/null +++ b/config/api_platform/resources/schedule/task.yaml @@ -0,0 +1,10 @@ +resources: + Pimcore\Bundle\StudioApiBundle\Dto\Task: + provider: Pimcore\Bundle\StudioApiBundle\State\ScheduledTaskProvider + normalizationContext: + groups: ['task:read'] + denormalizationContext: + groups: ['task:write'] + properties: + id: + identifier: true \ No newline at end of file diff --git a/config/api_platform/resources/user.yaml b/config/api_platform/resources/user.yaml index a78d2be1e..52d7888de 100644 --- a/config/api_platform/resources/user.yaml +++ b/config/api_platform/resources/user.yaml @@ -7,11 +7,6 @@ resources: input: Pimcore\Bundle\StudioApiBundle\Dto\ResetPasswordRequest output: false uriTemplate: '/users/reset-password' -# ApiPlatform\Metadata\Get: -# controller: ApiPlatform\Action\NotFoundAction -# read: false -# output: false - normalizationContext: groups: [ 'get' ] diff --git a/config/api_platform/resources/version.yaml b/config/api_platform/resources/version.yaml new file mode 100644 index 000000000..15478a634 --- /dev/null +++ b/config/api_platform/resources/version.yaml @@ -0,0 +1,16 @@ +resources: + Pimcore\Bundle\StudioApiBundle\Dto\Version: + operations: + ApiPlatform\Metadata\Get: + ApiPlatform\Metadata\Put: + ApiPlatform\Metadata\Post: + ApiPlatform\Metadata\Delete: + ApiPlatform\Metadata\Patch: + provider: Pimcore\Bundle\StudioApiBundle\State\VersionProvider + normalizationContext: + groups: ['version:read'] + denormalizationContext: + groups: ['version:write'] + properties: + id: + identifier: true \ No newline at end of file diff --git a/config/serialization/asset.yaml b/config/serialization/asset.yaml index 8cf84b184..19f50f772 100644 --- a/config/serialization/asset.yaml +++ b/config/serialization/asset.yaml @@ -1,64 +1,48 @@ -Pimcore\Model\Asset: +Pimcore\Bundle\StudioApiBundle\Dto\Asset: attributes: id: - groups: ['get', 'bla:read'] + groups: ['asset:read'] parentId: - groups: ['get'] + groups: ['asset:read'] + permissions: + groups: [ 'asset:read' ] type: - groups: ['get'] + groups: ['asset:read'] + children: + groups: ['asset:read'] filename: - groups: ['get'] + groups: ['asset:read'] path: - groups: ['get'] + groups: ['asset:read'] mimetype: - groups: ['get'] + groups: ['asset:read'] creationDate: - groups: ['get'] + groups: ['asset:read'] modificationDate: - groups: ['get'] + groups: ['asset:read'] userOwner: - groups: ['get'] + groups: ['asset:read'] userModification: - groups: ['get'] + groups: ['asset:read'] properties: - groups: ['get'] + groups: ['asset:item:get'] versions: - groups: ['get'] + groups: ['asset:read'] metadata: - groups: ['get'] + groups: ['asset:read'] locked: - groups: ['get'] + groups: ['asset:read'] + lock: + groups: ['asset:read'] customSettings: - groups: ['get'] + groups: ['asset:item:get'] hasMetaData: - groups: ['get'] + groups: ['asset:read'] dependencies: - groups: ['get'] + groups: ['asset:item:get'] scheduledTasks: - groups: ['get'] + groups: ['asset:item:get'] versionCount: - groups: ['get'] + groups: ['asset:item:get'] fullPath: - groups: ['get'] - -Pimcore\Model\Asset\Image: - attributes: - thumbnail: - groups: ['get'] - format: - groups: ['get'] - dimensions: - groups: ['get'] - width: - groups: [ 'get' ] - height: - groups: [ 'get' ] - -Pimcore\Model\Asset\Image\Thumbnail: - attributes: - path: - groups: ['get'] - imageTag: - groups: ['get'] - media: - groups: ['get'] \ No newline at end of file + groups: ['asset:read'] \ No newline at end of file diff --git a/config/serialization/asset/image.yaml b/config/serialization/asset/image.yaml new file mode 100644 index 000000000..7209d8484 --- /dev/null +++ b/config/serialization/asset/image.yaml @@ -0,0 +1,20 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image: + attributes: + thumbnail: + groups: ['image:read'] + format: + groups: ['image:read'] + dimensions: + groups: ['image:read'] + width: + groups: ['image:read'] + height: + groups: ['image:read'] + animated: + groups: ['image:read'] + vectorGraphic: + groups: ['image:read'] + lowQualityPreviewDataUri: + groups: ['image:read'] + lowQualityPreviewPath: + groups: ['image:read'] \ No newline at end of file diff --git a/config/serialization/asset/permissions.yaml b/config/serialization/asset/permissions.yaml new file mode 100644 index 000000000..5f452b976 --- /dev/null +++ b/config/serialization/asset/permissions.yaml @@ -0,0 +1,20 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Asset\Permissions: + attributes: + list: + groups: ['asset:read'] + view: + groups: ['asset:read'] + publish: + groups: ['asset:read'] + delete: + groups: ['asset:read'] + rename: + groups: ['asset:read'] + create: + groups: ['asset:read'] + settings: + groups: ['asset:read'] + versions: + groups: ['asset:read'] + properties: + groups: ['asset:read'] \ No newline at end of file diff --git a/config/serialization/dependency.yaml b/config/serialization/dependency.yaml new file mode 100644 index 000000000..94ca83435 --- /dev/null +++ b/config/serialization/dependency.yaml @@ -0,0 +1,16 @@ +Pimcore\Model\Dependency: + attributes: + sourceId: + groups: ['dependency:read'] + sourceType: + groups: ['dependency:read'] + required: + groups: ['dependency:read'] + requiredByTotalCount: + groups: ['dependency:read'] + requiresTotalCount: + groups: ['dependency:read'] + requires: + groups: ['dependency:read'] + requiredBy: + groups: ['dependency:read'] \ No newline at end of file diff --git a/config/serialization/property.yaml b/config/serialization/property.yaml new file mode 100644 index 000000000..1c58e48e5 --- /dev/null +++ b/config/serialization/property.yaml @@ -0,0 +1,18 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Property: + attributes: + name: + groups: ['property:read'] + data: + groups: ['property:read'] + type: + groups: ['property:read'] + ctype: + groups: ['property:read'] + cpath: + groups: ['property:read'] + cid: + groups: ['property:read'] + inheritable: + groups: ['property:read'] + inherited: + groups: ['property:read'] \ No newline at end of file diff --git a/config/serialization/schedule/task.yaml b/config/serialization/schedule/task.yaml new file mode 100644 index 000000000..0c512851d --- /dev/null +++ b/config/serialization/schedule/task.yaml @@ -0,0 +1,18 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Task: + attributes: + id: + groups: ['task:read', 'task:write'] + cid: + groups: ['task:read', 'task:write'] + ctype: + groups: ['task:read', 'task:write'] + date: + groups: ['task:read', 'task:write'] + action: + groups: ['task:read', 'task:write'] + version: + groups: ['task:read', 'task:write'] + active: + groups: ['task:read', 'task:write'] + userId: + groups: ['task:read', 'task:write'] \ No newline at end of file diff --git a/config/serialization/version.yaml b/config/serialization/version.yaml new file mode 100644 index 000000000..9ab5c5729 --- /dev/null +++ b/config/serialization/version.yaml @@ -0,0 +1,32 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Version: + attributes: + id: + groups: ['version:read', 'asset:item:get'] + cid: + groups: ['version:read', 'asset:item:get'] + ctype: + groups: ['version:read', 'asset:item:get'] + userId: + groups: ['version:read', 'asset:item:get'] + user: + groups: ['version:read', 'asset:item:get'] + note: + groups: ['version:read', 'asset:item:get'] + date: + groups: ['version:read', 'asset:item:get'] + data: + groups: ['version:read'] + public: + groups: ['version:read', 'asset:item:get'] + serialized: + groups: ['version:read', 'asset:item:get'] + versionCount: + groups: ['version:read', 'asset:item:get'] + binaryFileHash: + groups: ['version:read', 'asset:item:get'] + binaryFileId: + groups: ['version:read', 'asset:item:get'] + autosave: + groups: ['version:read', 'asset:item:get'] + storageType: + groups: ['version:read', 'asset:item:get'] diff --git a/config/services.yaml b/config/services.yaml index 6561874e7..6375b4f7c 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -19,9 +19,19 @@ services: public: true tags: [ 'controller.service_arguments' ] + # Providers Pimcore\Bundle\StudioApiBundle\State\AssetProvider: ~ + Pimcore\Bundle\StudioApiBundle\State\ScheduledTaskProvider: ~ + Pimcore\Bundle\StudioApiBundle\State\VersionProvider: ~ + + # Processors Pimcore\Bundle\StudioApiBundle\State\ResetPasswordProcessor: ~ + # Filters + Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter: + tags: [ 'api_platform.filter' ] + + # Normalizers Pimcore\Bundle\StudioApiBundle\Serializer\AssetNormalizer: tags: - - { name: 'serializer.normalizer' } \ No newline at end of file + - { name: 'serializer.normalizer' } diff --git a/src/Dto/Asset.php b/src/Dto/Asset.php new file mode 100644 index 000000000..94624862b --- /dev/null +++ b/src/Dto/Asset.php @@ -0,0 +1,173 @@ +permission; + } + + public function getId(): ?int + { + return $this->asset->getId(); + } + + public function getParentId(): ?int + { + return $this->asset->getParentId(); + } + + public function hasChildren(): bool + { + return $this->asset->hasChildren(); + } + + public function getUserModification(): ?int + { + return $this->asset->getUserModification(); + } + + public function getCreationDate(): ?int + { + return $this->asset->getCreationDate(); + } + + public function getModificationDate(): ?int + { + return $this->asset->getModificationDate(); + } + + public function getUserOwner(): ?int + { + return $this->asset->getUserOwner(); + } + + /** + * enum('self','propagate') nullable + * + */ + public function getLock(): ?string + { + return $this->asset->getLocked(); + } + + public function isLocked(): bool + { + return $this->asset->isLocked(); + } + + /** + * @return Property[] the $properties + */ + public function getProperties(): array + { + $properties = []; + foreach ($this->asset->getProperties() as $property) { + $properties[] = new Property($property); + } + return $properties; + } + + public function getVersionCount(): int + { + return $this->asset->getVersionCount(); + } + + public function getFilename(): ?string + { + return $this->asset->getFilename(); + } + + public function getKey(): ?string + { + return $this->asset->getKey(); + } + + public function getType(): string + { + return $this->asset->getType(); + } + + /** + * @return Version[] the $versions + */ + public function getVersions(): array + { + $versions = []; + foreach ($this->asset->getVersions() as $version) { + $versions[] = new Version($version); + } + return $versions; + } + + public function getCustomSettings(): array + { + return $this->asset->getCustomSettings(); + } + + public function getMimeType(): ?string + { + return $this->asset->getMimeType(); + } + + /** + * @return Task[] the $scheduledTasks + */ + public function getScheduledTasks(): array + { + $tasks = []; + foreach ($this->asset->getScheduledTasks() as $task) { + $tasks[] = new Task($task); + } + return $tasks; + } + + public function getPath(): ?string + { + return $this->asset->getPath(); + } + + public function getMetadata(): array + { + return $this->asset->getMetadata(); + } + #[ApiProperty(genId: false)] + public function getDependencies(): Dependency + { + return $this->asset->getDependencies(); + } + + public function getHasMetaData(): bool + { + return $this->asset->getHasMetaData(); + } + + public function getFullPath(): string + { + return $this->asset->getFullPath(); + } + + public function getFrontendFullPath(): string + { + return $this->asset->getFrontendFullPath(); + } + + public function getUserPermissions(?User $user = null): array + { + return $this->asset->getUserPermissions($user); + } +} diff --git a/src/Dto/Asset/Image.php b/src/Dto/Asset/Image.php new file mode 100644 index 000000000..70b84e4e9 --- /dev/null +++ b/src/Dto/Asset/Image.php @@ -0,0 +1,61 @@ +asset->getLowQualityPreviewPath(); + } + + public function getLowQualityPreviewDataUri(): ?string + { + return $this->asset->getLowQualityPreviewDataUri(); + } + + public function getThumbnail(array|string|ModelImage\Thumbnail\Config|null $config = null, bool $deferred = true): ThumbnailInterface + { + return $this->asset->getThumbnail($config, $deferred); + } + + public function getFormat(): string + { + return $this->asset->getFormat(); + } + + public function getDimensions(string $path = null, bool $force = false): ?array + { + return $this->asset->getDimensions($path, $force); + } + + public function getWidth(): int + { + return $this->asset->getWidth(); + } + + public function getHeight(): int + { + return $this->asset->getHeight(); + } + + public function isVectorGraphic(): bool + { + return $this->asset->isVectorGraphic(); + } + + public function isAnimated(): bool + { + return $this->asset->isAnimated(); + } +} \ No newline at end of file diff --git a/src/Dto/Asset/Permissions.php b/src/Dto/Asset/Permissions.php new file mode 100644 index 000000000..fc717a74a --- /dev/null +++ b/src/Dto/Asset/Permissions.php @@ -0,0 +1,66 @@ +list; + } + + public function isView(): bool + { + return $this->view; + } + + public function isPublish(): bool + { + return $this->publish; + } + + public function isDelete(): bool + { + return $this->delete; + } + + public function isRename(): bool + { + return $this->rename; + } + + public function isCreate(): bool + { + return $this->create; + } + + public function isSettings(): bool + { + return $this->settings; + } + + public function isVersions(): bool + { + return $this->versions; + } + + public function isProperties(): bool + { + return $this->properties; + } +} diff --git a/src/Dto/Property.php b/src/Dto/Property.php new file mode 100644 index 000000000..f80e74584 --- /dev/null +++ b/src/Dto/Property.php @@ -0,0 +1,56 @@ +property->getCid(); + } + + /** + * enum('document','asset','object') + */ + public function getCtype(): ?string + { + return $this->property->getCtype(); + } + + public function getData(): mixed + { + return $this->property->getData(); + } + + public function getName(): ?string + { + return $this->property->getName(); + } + + /** + * enum('text','document','asset','object','bool','select') + */ + public function getType(): ?string + { + return $this->property->getType(); + } + + public function getCpath(): ?string + { + return $this->property->getCpath(); + } + + public function isInherited(): bool + { + return $this->property->isInherited(); + } + + public function getInheritable(): bool + { + return $this->property->getInheritable(); + } +} \ No newline at end of file diff --git a/src/Dto/Task.php b/src/Dto/Task.php new file mode 100644 index 000000000..9987bca62 --- /dev/null +++ b/src/Dto/Task.php @@ -0,0 +1,41 @@ +task->getId(); + } + + public function getCid(): ?int + { + return $this->task->getCid(); + } + + public function getCtype(): ?string + { + return $this->task->getCtype(); + } + + public function getDate(): ?int + { + return $this->task->getDate(); + } + + public function getAction(): ?string + { + return $this->task->getAction(); + } + + public function getVersion(): ?int + { + return $this->task->getVersion(); + } +} \ No newline at end of file diff --git a/src/Dto/Version.php b/src/Dto/Version.php new file mode 100644 index 000000000..325b9c1f0 --- /dev/null +++ b/src/Dto/Version.php @@ -0,0 +1,110 @@ +version->getBinaryFileStream(); + } + + public function getId(): ?int + { + return $this->version->getId(); + } + + public function getCid(): int + { + return $this->version->getCid(); + } + + public function getCtype(): string + { + return $this->version->getCtype(); + } + + public function getDate(): int + { + return $this->version->getDate(); + } + + public function getFileStream(): mixed + { + return $this->version->getFileStream(); + } + + public function getNote(): string + { + return $this->version->getNote(); + } + + public function getUserId(): int + { + return $this->version->getUserId(); + } + + /** + * + * @return mixed + */ + public function getData(): mixed + { + $data = $this->version->getData(); + if ($data instanceof Image) { + return new \Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image($data, new Permissions()); + } + return $data; + } + + public function getSerialized(): bool + { + return $this->version->getSerialized(); + } + + public function getUser(): ?User + { + return $this->version->getUser(); + } + + public function isPublic(): bool + { + return $this->version->isPublic(); + } + + public function getVersionCount(): int + { + return $this->version->getVersionCount(); + } + + public function getBinaryFileHash(): ?string + { + return $this->version->getBinaryFileHash(); + } + + public function getBinaryFileId(): ?int + { + return $this->version->getBinaryFileId(); + } + + public function isAutoSave(): bool + { + return $this->version->isAutoSave(); + } + + public function getStorageType(): ?string + { + return $this->version->getStorageType(); + } +} \ No newline at end of file diff --git a/src/Filter/AssetParentIdFilter.php b/src/Filter/AssetParentIdFilter.php new file mode 100644 index 000000000..30506d183 --- /dev/null +++ b/src/Filter/AssetParentIdFilter.php @@ -0,0 +1,40 @@ +query->get('parentId'); + + if (!$parentId) { + return; + } + + $context[self::ASSET_PARENT_ID_FILTER_CONTEXT] = $parentId; + } + + public function getDescription(string $resourceClass): array + { + return [ + 'parentId' => [ + 'property' => Asset::class, + 'type' => 'int', + 'required' => true, + 'is_collection' => false, + 'description' => 'Filters assets by parent id.', + 'openapi' => [ + 'description' => 'Filters assets by parent id.', + ], + ] + ]; + } +} \ No newline at end of file diff --git a/src/Serializer/AssetNormalizer.php b/src/Serializer/AssetNormalizer.php index 02efee9ec..44eb13835 100644 --- a/src/Serializer/AssetNormalizer.php +++ b/src/Serializer/AssetNormalizer.php @@ -1,4 +1,5 @@ getThumbnail()->getPath(['frontend' => true]); + $data['thumbnailXXX'] = $object->getThumbnail()->getPath(['frontend' => true]); } return $data; @@ -47,6 +49,7 @@ public function normalize($object, $format = null, array $context = []): array public function supportsNormalization($data, $format = null, array $context = []): bool { + return false; if (isset($context[self::ALREADY_CALLED])) { return false; } diff --git a/src/State/AssetProvider.php b/src/State/AssetProvider.php index 0f56769b4..feff09435 100644 --- a/src/State/AssetProvider.php +++ b/src/State/AssetProvider.php @@ -15,29 +15,65 @@ use ApiPlatform\Metadata\CollectionOperationInterface; use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\Pagination\Pagination; +use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use Pimcore\Model\Asset; -use Pimcore\Model\Element\Tag; +use ArrayIterator; +use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\Search\Tree\AssetTreeServiceInterface; +use Pimcore\Bundle\StaticResolverBundle\Models\Asset\AssetResolverInterface; +use Pimcore\Bundle\StudioApiBundle\Dto\Asset; +use Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image; +use Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter; +use Pimcore\Model\Asset\Image as ImageModel; + final class AssetProvider implements ProviderInterface { + public function __construct( + private readonly AssetResolverInterface $assetResolver, + private readonly AssetTreeServiceInterface $assetTreeService, + private readonly Pagination $pagination + ) { + } + public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { - // collection of assets, needs to be further investigated if ($operation instanceof CollectionOperationInterface) { - $assetListing = new Asset\Listing(); - $assetListing->setLimit(10); - - if (isset($context['filters']['page'])) { - $assetListing->setOffset(10 * $context['filters']['page']); + $result =[]; + $totalItems = 0; + if (array_key_exists(AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT, $context)){ + $parentId = (int)($context[AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT] ?? 1); + $items = $this->assetTreeService->fetchTreeItems( + $parentId, + $this->pagination->getPage($context), + $this->pagination->getLimit($operation, $context) + ); + $totalItems = $items->getPagination()->getTotalItems(); + foreach ($items->getItems() as $item) { + $assetModel = $this->assetResolver->getById($item->getId()); + if ($assetModel === null) { + continue; + } + $result[] = new Asset($assetModel, new Asset\Permissions()); + } } - return $assetListing; + return new TraversablePaginator( + new ArrayIterator($result), + $this->pagination->getPage($context), + $this->pagination->getLimit($operation, $context), + $totalItems + ); } - // getting a single asset by id - $test = Asset::getById($uriVariables['id']); + $assetModel = $this->assetResolver->getById($uriVariables['id']); - //$tag = Tag::getTagsForElement('asset', $test->getId()); - return $test; + if ($assetModel === null) { + return null; + } + + if ($assetModel instanceof ImageModel) { + return new Image($assetModel, new Asset\Permissions()); + } + return new Asset($assetModel, new Asset\Permissions()); } } diff --git a/src/State/ScheduledTaskProvider.php b/src/State/ScheduledTaskProvider.php new file mode 100644 index 000000000..8caec692e --- /dev/null +++ b/src/State/ScheduledTaskProvider.php @@ -0,0 +1,42 @@ +taskResolver->getById($uriVariables['id']); + if ($task === null) { + return null; + } + + return new Task($task); + } +} diff --git a/src/State/VersionProvider.php b/src/State/VersionProvider.php new file mode 100644 index 000000000..9aa2ed110 --- /dev/null +++ b/src/State/VersionProvider.php @@ -0,0 +1,41 @@ +versionResolver->getById($uriVariables['id']); + if ($version === null) { + return null; + } + + return new Version($version); + } +}