diff --git a/src/Entity/Attachments/Attachment.php b/src/Entity/Attachments/Attachment.php index 098300a8..5916b603 100644 --- a/src/Entity/Attachments/Attachment.php +++ b/src/Entity/Attachments/Attachment.php @@ -22,7 +22,13 @@ declare(strict_types=1); namespace App\Entity\Attachments; -use App\Entity\Parts\PartTraits\ProjectTrait; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; use App\Repository\AttachmentRepository; use App\EntityListeners\AttachmentDeleteListener; use Doctrine\DBAL\Types\Types; @@ -30,6 +36,7 @@ use App\Entity\Base\AbstractNamedDBElement; use App\Validator\Constraints\Selectable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Validator\Constraints as Assert; use function in_array; use InvalidArgumentException; @@ -55,6 +62,18 @@ use LogicException; #[ORM\Index(name: 'attachments_idx_class_name_id', columns: ['class_name', 'id'])] #[ORM\Index(name: 'attachment_name_idx', columns: ['name'])] #[ORM\Index(name: 'attachment_element_idx', columns: ['class_name', 'element_id'])] + +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@attachments.list_attachments")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['attachment:read', 'attachment:read:standalone', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['attachment:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] abstract class Attachment extends AbstractNamedDBElement { /** @@ -102,22 +121,25 @@ abstract class Attachment extends AbstractNamedDBElement * @var string the name of this element */ #[Assert\NotBlank(message: 'validator.attachment.name_not_blank')] - #[Groups(['simple', 'extended', 'full'])] + #[Groups(['simple', 'extended', 'full', 'attachment:read', 'attachment:write'])] protected string $name = ''; /** * ORM mapping is done in subclasses (like PartAttachment). * @phpstan-param T|null $element */ + #[Groups(['attachment:read:standalone', 'attachment:read'])] protected ?AttachmentContainingDBElement $element = null; #[ORM\Column(type: Types::BOOLEAN)] + #[Groups(['attachment:read', 'attachment_write'])] protected bool $show_in_table = false; #[Assert\NotNull(message: 'validator.attachment.must_not_be_null')] #[ORM\ManyToOne(targetEntity: AttachmentType::class, inversedBy: 'attachments_with_type')] #[ORM\JoinColumn(name: 'type_id', nullable: false)] #[Selectable()] + #[Groups(['attachment:read', 'attachment_write'])] protected ?AttachmentType $attachment_type = null; public function __construct() @@ -147,6 +169,7 @@ abstract class Attachment extends AbstractNamedDBElement * @return bool * true if the file extension is a picture extension * * otherwise false */ + #[Groups(['attachment:read'])] public function isPicture(): bool { if ($this->isExternal()) { @@ -171,6 +194,8 @@ abstract class Attachment extends AbstractNamedDBElement * Check if this attachment is a 3D model and therefore can be directly shown to user. * If the attachment is external, false is returned (3D Models must be internal). */ + #[Groups(['attachment:read'])] + #[SerializedName('3d_model')] public function is3DModel(): bool { //We just assume that 3D Models are internally saved, otherwise we get problems loading them. @@ -188,6 +213,7 @@ abstract class Attachment extends AbstractNamedDBElement * * @return bool true, if the file is saved externally */ + #[Groups(['attachment:read'])] public function isExternal(): bool { //When path is empty, this attachment can not be external @@ -207,6 +233,8 @@ abstract class Attachment extends AbstractNamedDBElement * * @return bool true, if the file is secure */ + #[Groups(['attachment:read'])] + #[SerializedName('private')] public function isSecure(): bool { //After the %PLACEHOLDER% comes a slash, so we can check if we have a placeholder via explode @@ -221,6 +249,7 @@ abstract class Attachment extends AbstractNamedDBElement * * @return bool true if the attachment is using a builtin file */ + #[Groups(['attachment:read'])] public function isBuiltIn(): bool { return static::checkIfBuiltin($this->path); @@ -267,6 +296,8 @@ abstract class Attachment extends AbstractNamedDBElement * The URL to the external file, or the path to the built-in file. * Returns null, if the file is not external (and not builtin). */ + #[Groups(['attachment:read'])] + #[SerializedName('url')] public function getURL(): ?string { if (!$this->isExternal() && !$this->isBuiltIn()) { @@ -417,6 +448,8 @@ abstract class Attachment extends AbstractNamedDBElement * * @return Attachment */ + #[Groups(['attachment:write'])] + #[SerializedName('url')] public function setURL(?string $url): self { //Only set if the URL is not empty diff --git a/src/Entity/PriceInformations/Pricedetail.php b/src/Entity/PriceInformations/Pricedetail.php index 3202eb30..c46c3a46 100644 --- a/src/Entity/PriceInformations/Pricedetail.php +++ b/src/Entity/PriceInformations/Pricedetail.php @@ -42,6 +42,7 @@ use DateTime; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Validator\Constraints as Assert; /** @@ -189,6 +190,7 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface * @return BigDecimal the price as a bcmath string */ #[Groups(['pricedetail:read'])] + #[SerializedName('price_per_unit')] public function getPricePerUnit(float|string|BigDecimal $multiplier = 1.0): BigDecimal { $tmp = BigDecimal::of($multiplier); @@ -256,6 +258,7 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface * @return string|null */ #[Groups(['pricedetail:read'])] + #[SerializedName('currency_iso_code')] public function getCurrencyISOCode(): ?string { return $this->currency?->getIsoCode();