From 297df8048fb8515edc2a16be576432b2b39c4e86 Mon Sep 17 00:00:00 2001 From: roadiz-ci Date: Mon, 2 Dec 2024 18:14:22 +0000 Subject: [PATCH] feat!: Removed JMS Serializer annotation, AbstractAjaxController requires a Symfony Serializer interface --- src/Entity/Folder.php | 14 +- src/Entity/Group.php | 7 +- src/Entity/NodesSources.php | 25 +--- src/Entity/Realm.php | 4 +- src/Entity/Role.php | 3 +- src/Entity/Tag.php | 30 ++-- src/Entity/TagTranslation.php | 13 +- src/Entity/Translation.php | 34 ++--- src/Entity/User.php | 137 ++++-------------- .../Normalizer/DocumentNormalizer.php | 15 ++ 10 files changed, 86 insertions(+), 196 deletions(-) diff --git a/src/Entity/Folder.php b/src/Entity/Folder.php index 4d655f31..f2ff8c59 100644 --- a/src/Entity/Folder.php +++ b/src/Entity/Folder.php @@ -84,11 +84,6 @@ class Folder extends AbstractDateTimedPositioned implements FolderInterface, Lea /** @phpstan-ignore-next-line */ protected Collection $documents; - /** - * @Serializer\Groups({"folder", "folder_color"}) - * - * @Serializer\Type("string") - */ #[ORM\Column( name: 'color', type: 'string', @@ -99,6 +94,8 @@ class Folder extends AbstractDateTimedPositioned implements FolderInterface, Lea )] #[Assert\Length(max: 7)] #[SymfonySerializer\Groups(['folder', 'folder_color'])] + #[Serializer\Groups(['folder', 'folder_color'])] + #[Serializer\Type('string')] protected string $color = '#000000'; #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] @@ -219,12 +216,9 @@ public function getTranslatedFoldersByDefaultTranslation(): ?FolderTranslation }); } - /** - * @Serializer\VirtualProperty - * - * @Serializer\Groups({"folder", "document_folders"}) - */ #[SymfonySerializer\Groups(['folder', 'document_folders'])] + #[Serializer\Groups(['folder', 'document_folders'])] + #[Serializer\VirtualProperty] public function getName(): ?string { return $this->getTranslatedFolders()->first() ? diff --git a/src/Entity/Group.php b/src/Entity/Group.php index 599f1d5f..741f8a06 100644 --- a/src/Entity/Group.php +++ b/src/Entity/Group.php @@ -52,12 +52,9 @@ class Group extends AbstractEntity #[Serializer\Type("ArrayCollection")] private Collection $roleEntities; - /** - * @Serializer\Groups({"group", "user"}) - * - * @Serializer\Type("array") - */ #[SymfonySerializer\Groups(['group', 'user'])] + #[Serializer\Groups(['group', 'user'])] + #[Serializer\Type('array')] private ?array $roles = null; public function __construct() diff --git a/src/Entity/NodesSources.php b/src/Entity/NodesSources.php index 4d86338f..c18cc534 100644 --- a/src/Entity/NodesSources.php +++ b/src/Entity/NodesSources.php @@ -456,15 +456,11 @@ public function setNoIndex(bool $noIndex): NodesSources return $this; } - /** - * @Serializer\VirtualProperty - * - * @Serializer\SerializedName("slug") - * - * @Serializer\Groups({"nodes_sources", "nodes_sources_base"}) - */ #[SymfonySerializer\SerializedName('slug')] #[SymfonySerializer\Groups(['nodes_sources', 'nodes_sources_base'])] + #[Serializer\SerializedName('slug')] + #[Serializer\VirtualProperty] + #[Serializer\Groups(['nodes_sources', 'nodes_sources_base'])] public function getIdentifier(): string { $urlAlias = $this->getUrlAliases()->first(); @@ -484,11 +480,10 @@ public function getUrlAliases(): Collection } /** - * Get parent node’ source based on the same translation. - * - * @Serializer\Exclude + * Get parent node source based on the same translation. */ #[SymfonySerializer\Ignore] + #[Serializer\Exclude] public function getParent(): ?NodesSources { /** @var Node|null $parent */ @@ -538,15 +533,11 @@ public function setTranslation(TranslationInterface $translation): NodesSources return $this; } - /** - * @Serializer\VirtualProperty - * - * @Serializer\Groups({"nodes_sources", "nodes_sources_default"}) - * - * @Serializer\SerializedName("@type") - */ #[SymfonySerializer\Groups(['nodes_sources', 'nodes_sources_default'])] #[SymfonySerializer\SerializedName('@type')] + #[Serializer\Groups(['nodes_sources', 'nodes_sources_default'])] + #[Serializer\SerializedName('@type')] + #[Serializer\VirtualProperty] public function getNodeTypeName(): string { return 'NodesSources'; diff --git a/src/Entity/Realm.php b/src/Entity/Realm.php index 7f66eb4b..2f063c1e 100644 --- a/src/Entity/Realm.php +++ b/src/Entity/Realm.php @@ -61,11 +61,9 @@ class Realm extends AbstractEntity implements RealmInterface #[Assert\Regex('#^[\w\s]+$#u')] private string $name = ''; - /** - * @Serializer\Exclude() - */ #[ORM\Column(name: 'plain_password', type: 'string', length: 255, unique: false, nullable: true)] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] #[Assert\Length(max: 255)] private ?string $plainPassword = null; diff --git a/src/Entity/Role.php b/src/Entity/Role.php index 9c76c739..230df685 100644 --- a/src/Entity/Role.php +++ b/src/Entity/Role.php @@ -163,10 +163,9 @@ public function removeGroup(Group $group): Role * Get a classified version of current role name. * * It replaces underscores by dashes and lowercase. - * - * @Serializer\Groups({"role"}) */ #[SymfonySerializer\Groups(['role'])] + #[Serializer\Groups(['role'])] public function getClassName(): string { return str_replace('_', '-', \mb_strtolower($this->getRole())); diff --git a/src/Entity/Tag.php b/src/Entity/Tag.php index e166e3b1..9a3bd3a2 100644 --- a/src/Entity/Tag.php +++ b/src/Entity/Tag.php @@ -393,14 +393,10 @@ public function __toString(): string return (string) $this->getId(); } - /** - * @Serializer\Groups({"tag", "tag_base", "node", "nodes_sources"}) - * - * @Serializer\VirtualProperty - * - * @Serializer\Type("string|null") - */ #[SymfonySerializer\Ignore] + #[Serializer\Groups(['tag', 'tag_base', 'node', 'nodes_sources'])] + #[Serializer\VirtualProperty] + #[Serializer\Type('string|null')] public function getName(): ?string { return $this->getTranslatedTags()->first() ? @@ -432,14 +428,10 @@ public function setTranslatedTags(Collection $translatedTags): static return $this; } - /** - * @Serializer\Groups({"tag", "node", "nodes_sources"}) - * - * @Serializer\VirtualProperty - * - * @Serializer\Type("string|null") - */ #[SymfonySerializer\Ignore] + #[Serializer\VirtualProperty] + #[Serializer\Groups(['tag', 'node', 'nodes_sources'])] + #[Serializer\Type('string|null')] public function getDescription(): ?string { return $this->getTranslatedTags()->first() ? @@ -447,14 +439,10 @@ public function getDescription(): ?string ''; } - /** - * @Serializer\Groups({"tag", "node", "nodes_sources"}) - * - * @Serializer\VirtualProperty - * - * @Serializer\Type("array") - */ #[SymfonySerializer\Ignore] + #[Serializer\VirtualProperty] + #[Serializer\Groups(['tag', 'node', 'nodes_sources'])] + #[Serializer\Type('array')] public function getDocuments(): array { return $this->getTranslatedTags()->first() ? diff --git a/src/Entity/TagTranslation.php b/src/Entity/TagTranslation.php index 58e8b880..bb1d5125 100644 --- a/src/Entity/TagTranslation.php +++ b/src/Entity/TagTranslation.php @@ -58,8 +58,6 @@ class TagTranslation extends AbstractEntity /** * @var Collection - * - * @Serializer\Exclude */ #[ORM\OneToMany( mappedBy: 'tagTranslation', @@ -69,6 +67,7 @@ class TagTranslation extends AbstractEntity )] #[ORM\OrderBy(['position' => 'ASC'])] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] protected Collection $tagTranslationDocuments; /** @@ -151,14 +150,10 @@ public function __clone() } } - /** - * @Serializer\Groups({"tag"}) - * - * @Serializer\VirtualProperty - * - * @Serializer\Type("array") - */ #[SymfonySerializer\Groups(['tag'])] + #[Serializer\Groups(['tag'])] + #[Serializer\VirtualProperty] + #[Serializer\Type('array')] public function getDocuments(): array { return array_map(function (TagTranslationDocuments $tagTranslationDocument) { diff --git a/src/Entity/Translation.php b/src/Entity/Translation.php index 1ff9def6..d83812dc 100644 --- a/src/Entity/Translation.php +++ b/src/Entity/Translation.php @@ -549,13 +549,10 @@ class Translation extends AbstractDateTimed implements TranslationInterface * fr or en for example * * @see https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes - * - * @Serializer\Groups({"translation", "document", "nodes_sources", "tag", "attribute", "folder", "log_sources"}) - * - * @Serializer\Type("string") */ #[ORM\Column(type: 'string', length: 10, unique: true, nullable: false)] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] #[Assert\NotBlank] #[Assert\NotNull] #[Assert\Length(max: 10)] @@ -565,13 +562,9 @@ class Translation extends AbstractDateTimed implements TranslationInterface )] private string $locale = ''; - /** - * @Serializer\Groups({"translation", "document", "nodes_sources", "tag", "attribute", "folder"}) - * - * @Serializer\Type("string") - */ #[ORM\Column(name: 'override_locale', type: 'string', length: 10, unique: true, nullable: true)] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] #[Assert\Length(max: 10)] #[ApiProperty( description: 'Override standard locale with an other one (for example, `uk` instead of `en`)', @@ -579,13 +572,10 @@ class Translation extends AbstractDateTimed implements TranslationInterface )] private ?string $overrideLocale = null; - /** - * @Serializer\Groups({"translation", "translation_base"}) - * - * @Serializer\Type("string") - */ #[ORM\Column(type: 'string', length: 250, unique: true)] #[SymfonySerializer\Groups(['translation', 'translation_base'])] + #[Serializer\Groups(['translation', 'translation_base'])] + #[Serializer\Type('string')] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 250)] @@ -595,26 +585,20 @@ class Translation extends AbstractDateTimed implements TranslationInterface )] private string $name = ''; - /** - * @Serializer\Groups({"translation", "translation_base"}) - * - * @Serializer\Type("bool") - */ #[ORM\Column(name: 'default_translation', type: 'boolean', nullable: false, options: ['default' => false])] #[SymfonySerializer\Groups(['translation', 'translation_base'])] + #[Serializer\Groups(['translation', 'translation_base'])] + #[Serializer\Type('bool')] #[ApiProperty( description: 'Is translation default one?', example: 'true', )] private bool $defaultTranslation = false; - /** - * @Serializer\Groups({"translation", "translation_base"}) - * - * @Serializer\Type("bool") - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => true])] #[SymfonySerializer\Groups(['translation', 'translation_base'])] + #[Serializer\Groups(['translation', 'translation_base'])] + #[Serializer\Type('bool')] #[ApiProperty( description: 'Is translation available publicly?', example: 'true', @@ -778,6 +762,8 @@ public function setOverrideLocale(?string $overrideLocale): Translation */ #[SymfonySerializer\SerializedName('locale')] #[SymfonySerializer\Groups(['translation_base'])] + #[Serializer\SerializedName('locale')] + #[Serializer\Groups(['translation_base'])] #[ApiProperty( description: 'Translation ISO 639-1 locale. See https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes', example: 'fr', diff --git a/src/Entity/User.php b/src/Entity/User.php index 9a82b308..f0fc18fd 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -7,7 +7,6 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use JMS\Serializer\Annotation as Serializer; use Rollerworks\Component\PasswordStrength\Validator\Constraints\PasswordStrength; use RZ\Roadiz\Core\AbstractEntities\AbstractHuman; use RZ\Roadiz\CoreBundle\Form\Constraint\ValidFacebookName; @@ -17,7 +16,7 @@ use Symfony\Component\Security\Core\User\EquatableInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; -use Symfony\Component\Serializer\Annotation as SymfonySerializer; +use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Validator\Constraints as Assert; #[ @@ -48,11 +47,8 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface */ public const CONFIRMATION_TTL = 900; - /** - * @Serializer\Groups({"user_personal", "human"}) - */ #[ORM\Column(type: 'string', length: 200, unique: true, nullable: false)] - #[SymfonySerializer\Groups(['user_personal', 'human'])] + #[Serializer\Groups(['user_personal', 'human'])] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 200)] @@ -60,54 +56,35 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface /** @phpstan-ignore-next-line */ protected ?string $email = null; - /** - * @Serializer\Exclude() - */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] protected bool $sendCreationConfirmationEmail = false; #[ORM\Column(name: 'facebook_name', type: 'string', length: 128, unique: false, nullable: true)] - #[SymfonySerializer\Groups(['user_social'])] #[Serializer\Groups(['user_social'])] #[Assert\Length(max: 128)] #[ValidFacebookName] protected ?string $facebookName = null; - /** - * @Serializer\Groups({"user"}) - */ #[ORM\Column(name: 'picture_url', type: 'text', nullable: true)] - #[SymfonySerializer\Groups(['user'])] + #[Serializer\Groups(['user'])] #[Assert\Length(max: 250)] protected ?string $pictureUrl = null; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => true])] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] protected bool $enabled = true; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(name: 'confirmation_token', type: 'string', length: 128, unique: true, nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] #[Assert\Length(max: 128)] protected ?string $confirmationToken = null; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(name: 'password_requested_at', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] protected ?\DateTime $passwordRequestedAt = null; - /** - * @Serializer\Groups({"user_personal", "log_user"}) - */ #[ORM\Column(type: 'string', length: 200, unique: true)] - #[SymfonySerializer\Groups(['user_personal', 'log_user'])] + #[Serializer\Groups(['user_personal', 'log_user'])] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 200)] @@ -117,28 +94,21 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface * Encrypted password. */ #[ORM\Column(type: 'string', length: 128, nullable: false)] - #[SymfonySerializer\Ignore] - #[Serializer\Exclude] + #[Serializer\Ignore] #[Assert\Length(max: 128)] private string $password = ''; /** * Plain password. Used for model validation. * **Must not be persisted.**. - * - * @Serializer\Groups({"user:write"}) - * - * @PasswordStrength(minLength=8, minStrength=3) */ - #[SymfonySerializer\Groups(['user:write'])] + #[PasswordStrength(minStrength: 3, minLength: 8)] + #[Serializer\Groups(['user:write'])] #[Assert\NotBlank(groups: ['no_empty_password'])] private ?string $plainPassword = null; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(name: 'last_login', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private ?\DateTime $lastLogin = null; /** @@ -148,8 +118,7 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')] #[ORM\InverseJoinColumn(name: 'role_id', referencedColumnName: 'id', onDelete: 'CASCADE')] #[ORM\ManyToMany(targetEntity: Role::class)] - #[SymfonySerializer\Ignore] - #[Serializer\Exclude] + #[Serializer\Ignore] private Collection $roleEntities; /** @@ -158,56 +127,38 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface * * @var array|null */ - #[SymfonySerializer\Ignore] - #[Serializer\Exclude] + #[Serializer\Ignore] private ?array $roles = null; /** * @var Collection - * - * @Serializer\Groups({"user_group"}) */ #[ORM\JoinTable(name: 'users_groups')] #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')] #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')] #[ORM\ManyToMany(targetEntity: Group::class, inversedBy: 'users')] - #[SymfonySerializer\Groups(['user_group'])] + #[Serializer\Groups(['user_group'])] private Collection $groups; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => false])] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private bool $locked = false; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(name: 'credentials_expires_at', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private ?\DateTime $credentialsExpiresAt = null; - /** - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(name: 'expires_at', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private ?\DateTime $expiresAt = null; - /** - * @Serializer\Groups({"user_chroot"}) - */ #[ORM\ManyToOne(targetEntity: Node::class)] #[ORM\JoinColumn(name: 'chroot_id', referencedColumnName: 'id', onDelete: 'SET NULL')] - #[SymfonySerializer\Groups(['user_chroot'])] + #[Serializer\Groups(['user_chroot'])] private ?Node $chroot = null; - /** - * @Serializer\Groups({"user"}) - */ #[ORM\Column(name: 'locale', type: 'string', length: 7, nullable: true)] - #[SymfonySerializer\Groups(['user'])] + #[Serializer\Groups(['user'])] #[Assert\Length(max: 7)] private ?string $locale = null; @@ -242,10 +193,8 @@ public function willSendCreationConfirmationEmail(): bool /** * Get available username data, first name and last name * or username as a last try. - * - * @Serializer\Exclude() */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function getIdentifier(): string { if ('' != $this->getFirstName() && '' != $this->getLastName()) { @@ -257,13 +206,8 @@ public function getIdentifier(): string } } - /** - * @Serializer\Groups({"user_identifier", "user_personal"}) - * - * @Serializer\VirtualProperty() - */ - #[SymfonySerializer\SerializedName('identifier')] - #[SymfonySerializer\Groups(['user_identifier', 'user_personal'])] + #[Serializer\SerializedName('identifier')] + #[Serializer\Groups(['user_identifier', 'user_personal'])] public function getUserIdentifier(): string { return $this->username; @@ -538,12 +482,8 @@ public function removeGroup(Group $group): User * Get current user groups name. * * @return array Array of strings - * - * @Serializer\Groups({"user"}) - * - * @Serializer\VirtualProperty() */ - #[SymfonySerializer\Groups(['user'])] + #[Serializer\Groups(['user'])] public function getGroupNames(): array { $names = []; @@ -565,12 +505,8 @@ public function getGroupNames(): array * @return bool true if the user's account is non expired, false otherwise * * @see AccountExpiredException - * - * @Serializer\Groups({"user_security"}) - * - * @Serializer\VirtualProperty() */ - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] public function isAccountNonExpired(): bool { return null === $this->expiresAt || $this->expiresAt->getTimestamp() > time(); @@ -585,12 +521,8 @@ public function isAccountNonExpired(): bool * @return bool true if the user is not locked, false otherwise * * @see LockedException - * - * @Serializer\Groups({"user_security"}) - * - * @Serializer\VirtualProperty() */ - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] public function isAccountNonLocked(): bool { return !$this->locked; @@ -646,12 +578,10 @@ public function setChroot(?Node $chroot = null): User /** * Get prototype abstract Gravatar url. * - * @Serializer\Exclude() - * * @param string $type Default: "identicon" * @param string $size Default: "200" */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function getGravatarUrl(string $type = 'identicon', string $size = '200'): string { if (null !== $this->getEmail()) { @@ -703,7 +633,7 @@ public function setEnabled(bool $enabled): User * * @see CredentialsExpiredException */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function isCredentialsNonExpired(): bool { return null === $this->credentialsExpiresAt || $this->credentialsExpiresAt->getTimestamp() > time(); @@ -726,8 +656,8 @@ public function setExpiresAt(?\DateTime $expiresAt): User * * @return array */ - #[SymfonySerializer\SerializedName('roles')] - #[SymfonySerializer\Groups(['user_role'])] + #[Serializer\SerializedName('roles')] + #[Serializer\Groups(['user_role'])] public function getRoles(): array { if (null === $this->roles) { @@ -805,10 +735,7 @@ public function __unserialize(array $data): void ] = $data; } - /** - * @Serializer\Groups({"user_security"}) - */ - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] public function isSuperAdmin(): bool { return $this->hasRole(Role::ROLE_SUPERADMIN); @@ -827,7 +754,7 @@ public function hasRole(string $role): bool /** * Every field tested in this methods must be serialized in token. */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function isEqualTo(UserInterface $user): bool { if (!$user instanceof User) { diff --git a/src/Serializer/Normalizer/DocumentNormalizer.php b/src/Serializer/Normalizer/DocumentNormalizer.php index 58018e81..87bf4b95 100644 --- a/src/Serializer/Normalizer/DocumentNormalizer.php +++ b/src/Serializer/Normalizer/DocumentNormalizer.php @@ -10,6 +10,7 @@ use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\Documents\MediaFinders\EmbedFinderFactory; use RZ\Roadiz\Documents\Models\FolderInterface; +use RZ\Roadiz\Documents\UrlGenerators\DocumentUrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Stopwatch\Stopwatch; @@ -25,6 +26,7 @@ public function __construct( Stopwatch $stopwatch, private readonly FilesystemOperator $documentsStorage, private readonly EmbedFinderFactory $embedFinderFactory, + private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, ) { parent::__construct($decorated, $urlGenerator, $stopwatch); } @@ -111,6 +113,19 @@ public function normalize(mixed $object, ?string $format = null, array $context } } + if ( + !$object->isPrivate() + && \in_array('explorer_thumbnail', $serializationGroups, true) + ) { + $data['url'] = $this->documentUrlGenerator + ->setDocument($object) + ->setOptions([ + 'fit' => '250x200', + 'quality' => 60, + ]) + ->getUrl(); + } + $this->stopwatch->stop('normalizeDocument'); }