['carrier:item:read', 'default:read']], ), new Post( uriTemplate: '/carriers/{carrierId}/addresses', uriVariables: [ 'carrierId' => new Link(fromClass: Carrier::class, toProperty: 'carrier'), ], // read:false : pas de stade lecture du parent. Le Link toProperty // resoudrait l'enfant (SELECT CarrierAddress ... WHERE carrier = :id) // et casse en NonUniqueResult des >= 2 enfants. Le parent est rattache // manuellement par CarrierAddressProcessor::linkParent (404 si absent). read: false, security: "is_granted('transport.carriers.manage')", normalizationContext: ['groups' => ['carrier:item:read', 'default:read']], denormalizationContext: ['groups' => ['carrier:write:addresses']], processor: CarrierAddressProcessor::class, ), new Patch( security: "is_granted('transport.carriers.manage')", normalizationContext: ['groups' => ['carrier:item:read', 'default:read']], denormalizationContext: ['groups' => ['carrier:write:addresses']], processor: CarrierAddressProcessor::class, ), new Delete( security: "is_granted('transport.carriers.manage')", processor: CarrierAddressProcessor::class, ), ], )] #[ORM\Entity] #[ORM\Table(name: 'carrier_address')] #[ORM\Index(name: 'idx_carrier_address_carrier', columns: ['carrier_id'])] #[ORM\Index(name: 'idx_carrier_address_created_by', columns: ['created_by'])] #[ORM\Index(name: 'idx_carrier_address_updated_by', columns: ['updated_by'])] #[Auditable] class CarrierAddress implements TimestampableInterface, BlamableInterface { use TimestampableBlamableTrait; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] #[Groups(['carrier:item:read'])] private ?int $id = null; #[ORM\ManyToOne(targetEntity: Carrier::class, inversedBy: 'addresses')] #[ORM\JoinColumn(name: 'carrier_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] private ?Carrier $carrier = null; #[ORM\Column(length: 80, options: ['default' => 'France'])] #[Assert\Length(max: 80, maxMessage: 'Le pays ne peut dépasser {{ limit }} caractères.', normalizer: 'trim')] #[Groups(['carrier:item:read', 'carrier:write:addresses'])] private string $country = 'France'; // RG-4.06 : code postal a 4 ou 5 chiffres (pas de controle CP/ville serveur, // l'autocomplete BAN est front). Le Regex borne deja la longueur (<= 5) : pas // de Length redondant (whitelist EXCLUDED_LENGTH_MIRROR). Nullable : obligatoire // seulement si affrete (RG-4.05, garde CarrierAddressProcessor). #[ORM\Column(name: 'postal_code', length: 20, nullable: true)] #[Assert\Regex(pattern: '/^[0-9]{4,5}$/', message: 'Le code postal doit comporter 4 ou 5 chiffres.')] #[Groups(['carrier:item:read', 'carrier:write:addresses'])] private ?string $postalCode = null; #[ORM\Column(length: 120, nullable: true)] #[Assert\Length(max: 120, maxMessage: 'La ville ne peut dépasser {{ limit }} caractères.', normalizer: 'trim')] #[Groups(['carrier:item:read', 'carrier:write:addresses'])] private ?string $city = null; #[ORM\Column(length: 255, nullable: true)] #[Assert\Length(max: 255, maxMessage: 'L\'adresse ne peut dépasser {{ limit }} caractères.', normalizer: 'trim')] #[Groups(['carrier:item:read', 'carrier:write:addresses'])] private ?string $street = null; #[ORM\Column(name: 'street_complement', length: 255, nullable: true)] #[Assert\Length(max: 255, maxMessage: 'Le complément d\'adresse ne peut dépasser {{ limit }} caractères.', normalizer: 'trim')] #[Groups(['carrier:item:read', 'carrier:write:addresses'])] private ?string $streetComplement = null; #[ORM\Column(options: ['default' => 0])] private int $position = 0; public function getId(): ?int { return $this->id; } public function getCarrier(): ?Carrier { return $this->carrier; } public function setCarrier(?Carrier $carrier): static { $this->carrier = $carrier; return $this; } public function getCountry(): string { return $this->country; } public function setCountry(string $country): static { $this->country = $country; return $this; } public function getPostalCode(): ?string { return $this->postalCode; } public function setPostalCode(?string $postalCode): static { $this->postalCode = $postalCode; return $this; } public function getCity(): ?string { return $this->city; } public function setCity(?string $city): static { $this->city = $city; return $this; } public function getStreet(): ?string { return $this->street; } public function setStreet(?string $street): static { $this->street = $street; return $this; } public function getStreetComplement(): ?string { return $this->streetComplement; } public function setStreetComplement(?string $streetComplement): static { $this->streetComplement = $streetComplement; return $this; } public function getPosition(): int { return $this->position; } public function setPosition(int $position): static { $this->position = $position; return $this; } }