diff --git a/config/properties.yaml b/config/properties.yaml index edf402c73..25dc6a415 100644 --- a/config/properties.yaml +++ b/config/properties.yaml @@ -19,6 +19,9 @@ services: Pimcore\Bundle\StudioBackendBundle\Property\Service\PropertyHydratorServiceInterface: class: Pimcore\Bundle\StudioBackendBundle\Property\Service\PropertyHydratorService + Pimcore\Bundle\StudioBackendBundle\Property\Service\PropertyServiceInterface: + class: Pimcore\Bundle\StudioBackendBundle\Property\Service\PropertyService + Pimcore\Bundle\StudioBackendBundle\Property\Hydrator\DataPropertyHydratorInterface: class: Pimcore\Bundle\StudioBackendBundle\Property\Hydrator\DataPropertyHydrator @@ -27,3 +30,8 @@ services: Pimcore\Bundle\StudioBackendBundle\Property\Extractor\PropertyDataExtractorInterface: class: Pimcore\Bundle\StudioBackendBundle\Property\Extractor\PropertyDataExtractor + + Pimcore\Bundle\StudioBackendBundle\Property\Factory\PropertyFactoryInterface: + class: Pimcore\Bundle\StudioBackendBundle\Property\Factory\PropertyFactory + + diff --git a/src/Exception/NotWriteableException.php b/src/Exception/NotWriteableException.php new file mode 100644 index 000000000..2f1f9b97c --- /dev/null +++ b/src/Exception/NotWriteableException.php @@ -0,0 +1,31 @@ +name] )] - #[ElementTypeParameter] - #[QueryParameter] + #[ElementTypeParameter(false, null)] + #[FilterParameter] #[SuccessResponse( - description: 'Predefined properties based on type and query parameters', + description: 'Predefined properties filtered based on type and query parameters', content: new ItemsJson(PredefinedProperty::class) )] #[BadRequestResponse] @@ -76,7 +75,7 @@ public function __construct( #[MethodNotAllowedResponse] #[UnsupportedMediaTypeResponse] #[UnprocessableContentResponse] - public function getProperties(#[MapQueryString] PropertiesParameters $parameters): JsonResponse + public function getProperties(#[MapQueryString] PropertiesParameters $parameters = new PropertiesParameters()): JsonResponse { return $this->jsonResponse(['items' => $this->hydratorService->getHydratedProperties($parameters)]); } diff --git a/src/Property/Controller/CreateController.php b/src/Property/Controller/CreateController.php new file mode 100644 index 000000000..fa364e0a5 --- /dev/null +++ b/src/Property/Controller/CreateController.php @@ -0,0 +1,69 @@ +name] + )] + #[SuccessResponse( + description: 'Element Properties data as json', + content: new JsonContent(ref: PredefinedProperty::class, type: 'object') + )] + #[BadRequestResponse] + #[UnauthorizedResponse] + #[MethodNotAllowedResponse] + #[UnsupportedMediaTypeResponse] + #[UnprocessableContentResponse] + public function createProperty(): JsonResponse + { + $property = $this->propertyFactory->create(); + return $this->jsonResponse($this->hydratorService->getHydratedPredefinedProperty($property)); + } +} \ No newline at end of file diff --git a/src/Property/Controller/DeleteController.php b/src/Property/Controller/DeleteController.php new file mode 100644 index 000000000..879a50352 --- /dev/null +++ b/src/Property/Controller/DeleteController.php @@ -0,0 +1,73 @@ +name] + )] + #[IdParameter(type: 'property', schema: new Schema(type: 'string', example: 'alpha-numerical'))] + #[SuccessResponse( + description: 'Element Properties data as json', + content: new ItemsJson(DataProperty::class) + )] + #[UnauthorizedResponse] + #[NotFoundResponse] + #[MethodNotAllowedResponse] + #[UnsupportedMediaTypeResponse] + #[UnprocessableContentResponse] + public function deleteProperty(string $id): JsonResponse + { + $this->propertyService->deletePredefinedProperty($id); + return $this->jsonResponse(['id' => $id]); + } +} diff --git a/src/Property/Controller/GetController.php b/src/Property/Controller/GetController.php index 5f86a3bfd..b3e4a31b5 100644 --- a/src/Property/Controller/GetController.php +++ b/src/Property/Controller/GetController.php @@ -17,10 +17,10 @@ namespace Pimcore\Bundle\StudioBackendBundle\Property\Controller; use OpenApi\Attributes\Get; -use OpenApi\Attributes\JsonContent; use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\ElementTypeParameter; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\IdParameter; +use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content\ItemsJson; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\MethodNotAllowedResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\NotFoundResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\UnauthorizedResponse; @@ -48,11 +48,10 @@ public function __construct( #[Route('/properties/{elementType}/{id}', name: 'pimcore_studio_api_get_properties', methods: ['GET'])] //#[IsGranted('STUDIO_API')] - #[GET( + #[Get( path: self::API_PATH . '/properties/{elementType}/{id}', operationId: 'getPropertiesByTypeAndId', - description: 'Get properties based on the type and the id', - summary: 'Get properties by type and ID', + summary: 'Get properties for an element based on the element type and the element id', security: self::SECURITY_SCHEME, tags: [Tags::Properties->name] )] @@ -60,7 +59,7 @@ public function __construct( #[IdParameter(type: 'element')] #[SuccessResponse( description: 'Element Properties data as json', - content: new JsonContent(ref: DataProperty::class, type: 'object') + content: new ItemsJson(DataProperty::class) )] #[UnauthorizedResponse] #[NotFoundResponse] diff --git a/src/Property/Controller/PutController.php b/src/Property/Controller/PutController.php new file mode 100644 index 000000000..b52977083 --- /dev/null +++ b/src/Property/Controller/PutController.php @@ -0,0 +1,73 @@ +name] + )] + #[PropertyRequestBody] + #[SuccessResponse( + description: 'Element Properties data as json', + content: new JsonContent(ref: PredefinedProperty::class, type: 'object') + )] + #[BadRequestResponse] + #[UnauthorizedResponse] + #[MethodNotAllowedResponse] + #[UnsupportedMediaTypeResponse] + #[UnprocessableContentResponse] + public function updateProperty(#[MapRequestPayload] UpdatePredefinedProperty $updatePredefinedProperty): JsonResponse + { + $property = $this->propertyService->updatePredefinedProperty($updatePredefinedProperty); + return $this->jsonResponse($this->hydratorService->getHydratedPredefinedProperty($property)); + } +} \ No newline at end of file diff --git a/src/Property/Factory/PropertyFactory.php b/src/Property/Factory/PropertyFactory.php new file mode 100644 index 000000000..9ed25ff0e --- /dev/null +++ b/src/Property/Factory/PropertyFactory.php @@ -0,0 +1,47 @@ +isWriteable()) { + throw new NotWriteableException('Predefined Property'); + } + + $property = Predefined::create(); + $property->setCtype(ElementTypes::TYPE_DOCUMENT); + $property->setName('New Property'); + $property->setKey('new_key'); + $property->setType('text'); + $property->save(); + + return $property; + } +} \ No newline at end of file diff --git a/src/Property/Factory/PropertyFactoryInterface.php b/src/Property/Factory/PropertyFactoryInterface.php new file mode 100644 index 000000000..921655a54 --- /dev/null +++ b/src/Property/Factory/PropertyFactoryInterface.php @@ -0,0 +1,23 @@ +getDescription(), $property->getKey(), $property->getType(), + $property->getData(), $property->getConfig(), + $property->getCtype(), $property->getInheritable(), $property->getCreationDate(), $property->getModificationDate() diff --git a/src/Property/Repository.php b/src/Property/Repository.php index a979cf972..38c1f5845 100644 --- a/src/Property/Repository.php +++ b/src/Property/Repository.php @@ -16,7 +16,9 @@ namespace Pimcore\Bundle\StudioBackendBundle\Property; +use Pimcore\Bundle\StudioBackendBundle\Exception\PropertyNotFoundException; use Pimcore\Bundle\StudioBackendBundle\Property\Request\PropertiesParameters; +use Pimcore\Bundle\StudioBackendBundle\Property\Schema\UpdatePredefinedProperty; use Pimcore\Model\Property\Predefined; use Pimcore\Model\Property\Predefined\Listing as PropertiesListing; use Symfony\Contracts\Translation\TranslatorInterface; @@ -35,19 +37,54 @@ public function listProperties(PropertiesParameters $parameters): PropertiesList { $list = new PropertiesListing(); $type = $parameters->getElementType(); - $query = $parameters->getQuery(); + $filter = $parameters->getFilter(); $translator = $this->translator; - $list->setFilter(static function (Predefined $predefined) use ($type, $query, $translator) { - if (!str_contains($predefined->getCtype(), $type)) { + + $list->setFilter(static function (Predefined $predefined) use ($type, $filter, $translator) { + + if ($type && !str_contains($predefined->getCtype(), $type)) { return false; } - if ($query && stripos($translator->trans($predefined->getName(), [], 'admin'), $query) === false) { + if ($filter && stripos($translator->trans($predefined->getName(), [], 'admin'), $filter) === false) { return false; } return true; }); - + return $list; } + + public function updatePredefinedProperty(UpdatePredefinedProperty $property): Predefined + { + $predefined = Predefined::getById($property->getId()); + + if (!$predefined) { + throw new PropertyNotFoundException($property->getId()); + } + + $predefined->setName($property->getName()); + $predefined->setDescription($property->getDescription()); + $predefined->setKey($property->getKey()); + $predefined->setType($property->getType()); + $predefined->setData($property->getData()); + $predefined->setConfig($property->getConfig()); + $predefined->setCtype($property->getCtype()); + $predefined->setInheritable($property->getInheritable()); + + $predefined->save(); + + return $predefined; + } + + public function deletePredefinedProperty(string $id): void + { + $predefined = Predefined::getById($id); + + if (!$predefined) { + throw new PropertyNotFoundException($id); + } + + $predefined->delete(); + } } diff --git a/src/Property/RepositoryInterface.php b/src/Property/RepositoryInterface.php index 55119be0d..74997b074 100644 --- a/src/Property/RepositoryInterface.php +++ b/src/Property/RepositoryInterface.php @@ -17,6 +17,8 @@ namespace Pimcore\Bundle\StudioBackendBundle\Property; use Pimcore\Bundle\StudioBackendBundle\Property\Request\PropertiesParameters; +use Pimcore\Bundle\StudioBackendBundle\Property\Schema\UpdatePredefinedProperty; +use Pimcore\Model\Property\Predefined; use Pimcore\Model\Property\Predefined\Listing as PropertiesListing; /** @@ -25,4 +27,8 @@ interface RepositoryInterface { public function listProperties(PropertiesParameters $parameters): PropertiesListing; + + public function updatePredefinedProperty(UpdatePredefinedProperty $property): Predefined; + + public function deletePredefinedProperty(string $id): void; } diff --git a/src/Property/Request/PropertiesParameters.php b/src/Property/Request/PropertiesParameters.php index 2c4c9f648..4e42e8aa1 100644 --- a/src/Property/Request/PropertiesParameters.php +++ b/src/Property/Request/PropertiesParameters.php @@ -24,18 +24,18 @@ final readonly class PropertiesParameters { public function __construct( - private string $elementType, - private ?string $query = null + private ?string $elementType = null, + private ?string $filter = null ) { } - public function getQuery(): ?string + public function getFilter(): ?string { - return $this->query; + return $this->filter; } - public function getElementType(): string + public function getElementType(): ?string { if ($this->elementType === ElementTypes::TYPE_DATA_OBJECT) { return ElementTypes::TYPE_OBJECT; diff --git a/src/Property/Schema/PredefinedProperty.php b/src/Property/Schema/PredefinedProperty.php index 1757d7adb..bf98d83ed 100644 --- a/src/Property/Schema/PredefinedProperty.php +++ b/src/Property/Schema/PredefinedProperty.php @@ -39,8 +39,12 @@ public function __construct( private string $key, #[Property(description: 'type', type: 'string', example: 'text')] private string $type, + #[Property(description: 'data', type: 'string', example: 'test')] + private ?string $data, #[Property(description: 'config', type: 'string', example: 'comma,separated,values')] private ?string $config, + #[Property(description: 'ctype', type: 'string', example: 'document')] + private string $ctype, #[Property(description: 'inheritable', type: 'boolean', example: false)] private bool $inheritable, #[Property(description: 'Creation date', type: 'integer', example: 221846400)] @@ -75,12 +79,22 @@ public function getType(): string return $this->type; } + public function getData(): ?string + { + return $this->data; + } + public function getConfig(): ?string { return $this->config; } - public function getIsInheritable(): bool + public function getCtype(): string + { + return $this->ctype; + } + + public function getInheritable(): bool { return $this->inheritable; } diff --git a/src/Property/Schema/UpdatePredefinedProperty.php b/src/Property/Schema/UpdatePredefinedProperty.php new file mode 100644 index 000000000..41a8fb935 --- /dev/null +++ b/src/Property/Schema/UpdatePredefinedProperty.php @@ -0,0 +1,97 @@ +id; + } + + public function getName(): string + { + return $this->name; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function getKey(): string + { + return $this->key; + } + + public function getType(): string + { + return $this->type; + } + + public function getData(): ?string + { + return $this->data; + } + + public function getConfig(): ?string + { + return $this->config; + } + + public function getCtype(): string + { + return $this->ctype; + } + + public function getInheritable(): bool + { + return $this->inheritable; + } +} diff --git a/src/Property/Service/PropertyHydratorService.php b/src/Property/Service/PropertyHydratorService.php index 386b0be98..98202a7af 100644 --- a/src/Property/Service/PropertyHydratorService.php +++ b/src/Property/Service/PropertyHydratorService.php @@ -23,6 +23,7 @@ use Pimcore\Bundle\StudioBackendBundle\Property\Request\PropertiesParameters; use Pimcore\Bundle\StudioBackendBundle\Property\Schema\PredefinedProperty; use Pimcore\Bundle\StudioBackendBundle\Util\Traits\ElementProviderTrait; +use Pimcore\Model\Property\Predefined; final readonly class PropertyHydratorService implements PropertyHydratorServiceInterface { @@ -32,7 +33,7 @@ public function __construct( private RepositoryInterface $repository, private ServiceResolver $serviceResolver, private DataPropertyHydratorInterface $dataPropertyHydrator, - private PredefinedPropertyHydratorInterface $propertyHydrator, + private PredefinedPropertyHydratorInterface $predefinedPropertyHydrator, ) { } @@ -44,7 +45,7 @@ public function getHydratedProperties(PropertiesParameters $parameters): array $properties = $this->repository->listProperties($parameters); $hydratedProperties = []; foreach ($properties->load() as $property) { - $hydratedProperties[] = $this->propertyHydrator->hydrate($property); + $hydratedProperties[] = $this->predefinedPropertyHydrator->hydrate($property); } return $hydratedProperties; @@ -60,6 +61,11 @@ public function getHydratedPropertyForElement(string $elementType, int $id): arr $hydratedProperties[] = $this->dataPropertyHydrator->hydrate($property); } - return $hydratedProperties; + return ['items' => $hydratedProperties]; + } + + public function getHydratedPredefinedProperty(Predefined $predefined): PredefinedProperty + { + return $this->predefinedPropertyHydrator->hydrate($predefined); } } diff --git a/src/Property/Service/PropertyHydratorServiceInterface.php b/src/Property/Service/PropertyHydratorServiceInterface.php index 3d9bb4260..1bc0a345f 100644 --- a/src/Property/Service/PropertyHydratorServiceInterface.php +++ b/src/Property/Service/PropertyHydratorServiceInterface.php @@ -18,6 +18,7 @@ use Pimcore\Bundle\StudioBackendBundle\Property\Request\PropertiesParameters; use Pimcore\Bundle\StudioBackendBundle\Property\Schema\PredefinedProperty; +use Pimcore\Model\Property\Predefined; interface PropertyHydratorServiceInterface { @@ -27,4 +28,6 @@ interface PropertyHydratorServiceInterface public function getHydratedProperties(PropertiesParameters $parameters): array; public function getHydratedPropertyForElement(string $elementType, int $id): array; + + public function getHydratedPredefinedProperty(Predefined $predefined): PredefinedProperty; } diff --git a/src/Property/Service/PropertyService.php b/src/Property/Service/PropertyService.php new file mode 100644 index 000000000..0aa128628 --- /dev/null +++ b/src/Property/Service/PropertyService.php @@ -0,0 +1,43 @@ +repository->updatePredefinedProperty($property); + } + + public function deletePredefinedProperty(string $id): void + { + $this->repository->deletePredefinedProperty($id); + } +} \ No newline at end of file diff --git a/src/Property/Service/PropertyServiceInterface.php b/src/Property/Service/PropertyServiceInterface.php new file mode 100644 index 000000000..579885a2d --- /dev/null +++ b/src/Property/Service/PropertyServiceInterface.php @@ -0,0 +1,29 @@ +