From 85656741213a3d0c04af7998aa909618d524dcba Mon Sep 17 00:00:00 2001 From: silverbackdan Date: Sun, 10 May 2026 08:36:57 +0100 Subject: [PATCH 1/4] Initial config and dependency updates --- composer.json | 19 ++++++++----------- .../Extension/ORM/TablePrefixExtension.php | 16 ++++++++++++---- .../Doctrine/PropagateUpdatesListener.php | 8 ++++++-- .../Doctrine/PublishableListener.php | 9 ++++++--- .../Doctrine/TimestampedListener.php | 4 ++-- .../Doctrine/UploadableListener.php | 4 ++-- .../doctrine-orm/Core.ComponentGroup.orm.xml | 2 +- .../doctrine-orm/User.AbstractUser.orm.xml | 2 +- .../ComponentPositionNormalizer.php | 4 ++-- .../Normalizer/PublishableNormalizer.php | 18 ++++-------------- .../Entity/DummyUploadableAndPublishable.php | 1 - .../app/config/packages/doctrine.yaml | 1 - 12 files changed, 44 insertions(+), 44 deletions(-) diff --git a/composer.json b/composer.json index 308658fe..e4a514c8 100644 --- a/composer.json +++ b/composer.json @@ -26,11 +26,10 @@ "ext-simplexml": "*", "api-platform/core": "^4.2", "cocur/slugify": "^4.1", - "doctrine/annotations": "^1.7.0", - "doctrine/dbal": "^3.4", - "doctrine/doctrine-bundle": "^2.7", - "doctrine/doctrine-migrations-bundle": "^3.2", - "doctrine/orm": "^2.9", + "doctrine/dbal": "^4.0", + "doctrine/doctrine-bundle": "^3.2", + "doctrine/doctrine-migrations-bundle": "^3.7", + "doctrine/orm": "^3.6", "imagine/imagine": "^1.3", "lcobucci/clock": "^2.0|^3.0", "lexik/jwt-authentication-bundle": "^3.1", @@ -40,7 +39,7 @@ "phpdocumentor/reflection-docblock": "^5.3", "ramsey/collection": "^1.2", "ramsey/uuid": "^4.5", - "ramsey/uuid-doctrine": "^1.6", + "ramsey/uuid-doctrine": "^2.1", "symfony/asset": "^7.2", "symfony/console": "^7.2", "symfony/doctrine-bridge": "^7.2", @@ -56,6 +55,7 @@ "symfony/twig-bundle": "^7.4", "symfony/type-info": "^7.4", "symfony/validator": "^7.4", + "symfony/var-exporter": "^8", "twig/cssinliner-extra": "^3.0.3", "twig/extra-bundle": "^3.0.3", "twig/inky-extra": "^3.0.3", @@ -65,8 +65,7 @@ "behat/behat": "^3.13", "behat/mink": "*", "behatch/contexts": "dev-master", - "doctrine/common": "^3.1", - "doctrine/doctrine-fixtures-bundle": "^3.4", + "doctrine/doctrine-fixtures-bundle": "^4.3", "friends-of-behat/mink-browserkit-driver": "^1.6", "friends-of-behat/mink-extension": "^2.7", "friends-of-behat/symfony-extension": "^2.4", @@ -87,7 +86,6 @@ "roave/security-advisories": "dev-master", "symfony/browser-kit": "^7.4", "symfony/css-selector": "^7.4", - "symfony/debug": "^4", "symfony/dotenv": "^7.4", "symfony/http-client": "^7.4", "symfony/maker-bundle": "^1.0", @@ -140,7 +138,6 @@ "symfony/serializer": "<=6.1.2", "symfony/var-exporter": "<6.1", "symfony/web-link": "<=6.0", - "doctrine/collections": "<1.7", - "doctrine/orm": "<2.13" + "doctrine/collections": "<1.7" } } diff --git a/src/Doctrine/Extension/ORM/TablePrefixExtension.php b/src/Doctrine/Extension/ORM/TablePrefixExtension.php index f1b9da8e..9e2f94c9 100644 --- a/src/Doctrine/Extension/ORM/TablePrefixExtension.php +++ b/src/Doctrine/Extension/ORM/TablePrefixExtension.php @@ -13,7 +13,7 @@ use Doctrine\ORM\Event\LoadClassMetadataEventArgs; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ManyToManyOwningSideMapping; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; /** @@ -61,10 +61,18 @@ private function setPrimaryTable(ClassMetadata $classMetadata): void private function setJoinTableName(ClassMetadata $classMetadata): void { foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) { - if (ClassMetadataInfo::MANY_TO_MANY === $mapping['type'] && $mapping['isOwningSide'] && !\array_key_exists('inherited', $mapping)) { - $mappedTableName = $mapping['joinTable']['name']; - $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName; + if (!$mapping instanceof ManyToManyOwningSideMapping) { + continue; } + + if ($mapping->inherited !== null) { + continue; + } + + $mapping->joinTable->name = $this->prefix . $mapping->joinTable->name; + + // May not be needed, because $mapping is already the same object stored internally. + $classMetadata->associationMappings[$fieldName] = $mapping; } } diff --git a/src/EventListener/Doctrine/PropagateUpdatesListener.php b/src/EventListener/Doctrine/PropagateUpdatesListener.php index afa26283..b0dc80ee 100644 --- a/src/EventListener/Doctrine/PropagateUpdatesListener.php +++ b/src/EventListener/Doctrine/PropagateUpdatesListener.php @@ -16,7 +16,6 @@ use ApiPlatform\Metadata\IriConverterInterface; use ApiPlatform\Metadata\ResourceClassResolverInterface; use ApiPlatform\Metadata\UrlGeneratorInterface; -use Doctrine\Common\Util\ClassUtils; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Event\PostFlushEventArgs; @@ -25,6 +24,7 @@ use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectRepository; +use Doctrine\Persistence\Proxy; use Silverback\ApiComponentsBundle\DataProvider\PageDataProvider; use Silverback\ApiComponentsBundle\Entity\Component\Collection; use Silverback\ApiComponentsBundle\Entity\Core\PageDataInterface; @@ -121,7 +121,11 @@ private function gatherResourceAndAssociated(object $entity, string $type, Objec $changeSet = $uow->getEntityChangeSet($entity); $this->collectUpdatedResource($entity, $type); - $associationMappings = $em->getClassMetadata(ClassUtils::getClass($entity))->getAssociationMappings(); + $class = $entity instanceof Proxy + ? get_parent_class($entity) + : $entity::class; + + $associationMappings = $em->getClassMetadata($class)->getAssociationMappings(); if ($entity instanceof PageDataInterface) { $this->pageDataPropertiesChanged = array_keys($changeSet); diff --git a/src/EventListener/Doctrine/PublishableListener.php b/src/EventListener/Doctrine/PublishableListener.php index a9cf0c79..a5b52e24 100644 --- a/src/EventListener/Doctrine/PublishableListener.php +++ b/src/EventListener/Doctrine/PublishableListener.php @@ -12,7 +12,7 @@ namespace Silverback\ApiComponentsBundle\EventListener\Doctrine; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\Event\LoadClassMetadataEventArgs; use Silverback\ApiComponentsBundle\AttributeReader\PublishableAttributeReader; @@ -30,7 +30,7 @@ public function __construct(PublishableAttributeReader $publishableStatusChecker public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void { - /** @var ClassMetadataInfo $metadata */ + /** @var ClassMetadata $metadata */ $metadata = $eventArgs->getClassMetadata(); if (!$this->publishableStatusChecker->isConfigured($metadata->getName())) { return; @@ -61,7 +61,10 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void 'targetEntity' => $metadata->getName(), 'joinColumns' => [ [ - 'name' => $namingStrategy->joinKeyColumnName($metadata->getName()), + 'name' => $namingStrategy->joinKeyColumnName( + $configuration->associationName, + $metadata->getName() + ), 'referencedColumnName' => $namingStrategy->referenceColumnName(), 'onDelete' => 'SET NULL', 'nullable' => true, diff --git a/src/EventListener/Doctrine/TimestampedListener.php b/src/EventListener/Doctrine/TimestampedListener.php index 56b39923..367f3e50 100644 --- a/src/EventListener/Doctrine/TimestampedListener.php +++ b/src/EventListener/Doctrine/TimestampedListener.php @@ -11,7 +11,7 @@ namespace Silverback\ApiComponentsBundle\EventListener\Doctrine; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\Event\LoadClassMetadataEventArgs; use Silverback\ApiComponentsBundle\AttributeReader\TimestampedAttributeReader; @@ -29,7 +29,7 @@ public function __construct(TimestampedAttributeReader $annotationReader) public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void { - /** @var ClassMetadataInfo $metadata */ + /** @var ClassMetadata $metadata */ $metadata = $eventArgs->getClassMetadata(); if (!$this->annotationReader->isConfigured($metadata->getName())) { return; diff --git a/src/EventListener/Doctrine/UploadableListener.php b/src/EventListener/Doctrine/UploadableListener.php index d83f01d6..9f084851 100644 --- a/src/EventListener/Doctrine/UploadableListener.php +++ b/src/EventListener/Doctrine/UploadableListener.php @@ -12,7 +12,7 @@ namespace Silverback\ApiComponentsBundle\EventListener\Doctrine; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\Event\LoadClassMetadataEventArgs; use Silverback\ApiComponentsBundle\AttributeReader\UploadableAttributeReader; @@ -30,7 +30,7 @@ public function __construct(UploadableAttributeReader $uploadableAnnotationReade public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void { - /** @var ClassMetadataInfo $metadata */ + /** @var ClassMetadata $metadata */ $metadata = $eventArgs->getClassMetadata(); $className = $metadata->getName(); if (!$this->uploadableAnnotationReader->isConfigured($className)) { diff --git a/src/Resources/config/doctrine-orm/Core.ComponentGroup.orm.xml b/src/Resources/config/doctrine-orm/Core.ComponentGroup.orm.xml index ebb4d8a6..9e87d25a 100644 --- a/src/Resources/config/doctrine-orm/Core.ComponentGroup.orm.xml +++ b/src/Resources/config/doctrine-orm/Core.ComponentGroup.orm.xml @@ -16,6 +16,6 @@ - + diff --git a/src/Resources/config/doctrine-orm/User.AbstractUser.orm.xml b/src/Resources/config/doctrine-orm/User.AbstractUser.orm.xml index 439fd2d2..f59a5497 100644 --- a/src/Resources/config/doctrine-orm/User.AbstractUser.orm.xml +++ b/src/Resources/config/doctrine-orm/User.AbstractUser.orm.xml @@ -8,7 +8,7 @@ - + diff --git a/src/Serializer/Normalizer/ComponentPositionNormalizer.php b/src/Serializer/Normalizer/ComponentPositionNormalizer.php index 995019c8..59c39420 100644 --- a/src/Serializer/Normalizer/ComponentPositionNormalizer.php +++ b/src/Serializer/Normalizer/ComponentPositionNormalizer.php @@ -12,7 +12,7 @@ namespace Silverback\ApiComponentsBundle\Serializer\Normalizer; use ApiPlatform\Metadata\IriConverterInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\ManagerRegistry; use Silverback\ApiComponentsBundle\DataProvider\PageDataProvider; use Silverback\ApiComponentsBundle\Entity\Core\AbstractComponent; @@ -135,7 +135,7 @@ private function normalizePublishableComponent(AbstractComponent $component) if (!$em) { throw new InvalidArgumentException(\sprintf('Could not find entity manager for class %s', $type)); } - /** @var ClassMetadataInfo $classMetadata */ + /** @var ClassMetadata $classMetadata */ $classMetadata = $em->getClassMetadata($type); $draft = $classMetadata->getFieldValue($component, $configuration->reverseAssociationName); diff --git a/src/Serializer/Normalizer/PublishableNormalizer.php b/src/Serializer/Normalizer/PublishableNormalizer.php index 60b2ed12..86856c78 100644 --- a/src/Serializer/Normalizer/PublishableNormalizer.php +++ b/src/Serializer/Normalizer/PublishableNormalizer.php @@ -15,7 +15,7 @@ use ApiPlatform\Validator\Exception\ValidationException; use ApiPlatform\Validator\ValidatorInterface; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; use Silverback\ApiComponentsBundle\Annotation\Publishable; @@ -84,7 +84,7 @@ public function normalize($object, $format = null, array $context = []): float|a $configuration = $this->publishableStatusChecker->getAttributeReader()->getConfiguration($type); $em = $this->getManagerFromType($type); - $classMetadata = $this->getClassMetadataInfo($em, $type); + $classMetadata = $em->getClassMetadata($type); $publishedAtDateTime = $classMetadata->getFieldValue($object, $configuration->fieldName); if ($publishedAtDateTime instanceof \DateTimeInterface) { @@ -213,7 +213,7 @@ private function unsetRestrictedData($type, array $data, Publishable $configurat public function createDraft(object $object, Publishable $configuration, string $type): object { $em = $this->getManagerFromType($type); - $classMetadata = $this->getClassMetadataInfo($em, $type); + $classMetadata = $em->getClassMetadata($type); // Resource is a draft: nothing to do here anymore if (null !== $classMetadata->getFieldValue($object, $configuration->associationName)) { @@ -234,7 +234,7 @@ public function createDraft(object $object, Publishable $configuration, string $ // Clear any writable one-to-many fields, these should still reference the published component, such as component positions // Doesn't matter usually it seems, but where we process uploadable, the one-to-many is not then reassigned later back to the publishable during normalization foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) { - if (ClassMetadataInfo::ONE_TO_MANY === $mapping['type'] && $this->propertyAccessor->isWritable($draft, $fieldName)) { + if (ClassMetadata::ONE_TO_MANY === $mapping['type'] && $this->propertyAccessor->isWritable($draft, $fieldName)) { $this->propertyAccessor->setValue($draft, $fieldName, new ArrayCollection()); } } @@ -272,16 +272,6 @@ private function getManagerFromType(string $type): ObjectManager return $em; } - private function getClassMetadataInfo(ObjectManager $em, string $type): ClassMetadataInfo - { - $classMetadata = $em->getClassMetadata($type); - if (!$classMetadata instanceof ClassMetadataInfo) { - throw new InvalidArgumentException(\sprintf('Class metadata for %s was not an instance of %s', $type, ClassMetadataInfo::class)); - } - - return $classMetadata; - } - public function getSupportedTypes(?string $format): array { return ['object' => false]; diff --git a/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php b/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php index 5684ff68..fd22bc25 100644 --- a/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php +++ b/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php @@ -29,7 +29,6 @@ #[ORM\Entity] class DummyUploadableAndPublishable extends AbstractComponent { - use IdTrait; use PublishableTrait; use UploadableTrait; diff --git a/tests/Functional/app/config/packages/doctrine.yaml b/tests/Functional/app/config/packages/doctrine.yaml index 45127049..db7f0360 100644 --- a/tests/Functional/app/config/packages/doctrine.yaml +++ b/tests/Functional/app/config/packages/doctrine.yaml @@ -4,7 +4,6 @@ doctrine: path: '%kernel.cache_dir%/../../db.sqlite' charset: 'UTF8' orm: - auto_generate_proxy_classes: '%kernel.debug%' naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware auto_mapping: false mappings: From a9ab1852c3756865597fb0efb464830ac2270647 Mon Sep 17 00:00:00 2001 From: silverbackdan Date: Sun, 10 May 2026 10:59:26 +0100 Subject: [PATCH 2/4] Mostly updated and fixed --- features/bootstrap/DoctrineContext.php | 2 +- .../Extension/ORM/PublishableExtension.php | 2 +- .../Doctrine/PublishableListener.php | 5 ++-- .../Doctrine/TimestampedListener.php | 1 - src/Filter/OrSearchFilter.php | 1 - src/Mercure/MercureResourcePublisher.php | 29 +++++++++---------- src/RefreshToken/RefreshToken.php | 6 ++-- .../Core.AbstractRefreshToken.orm.xml | 4 +-- 8 files changed, 24 insertions(+), 26 deletions(-) diff --git a/features/bootstrap/DoctrineContext.php b/features/bootstrap/DoctrineContext.php index 2314beae..8ca65725 100644 --- a/features/bootstrap/DoctrineContext.php +++ b/features/bootstrap/DoctrineContext.php @@ -885,7 +885,7 @@ public function iHaveARefreshToken(string $expiresAt = '+10 seconds'): void $refreshToken ->setUser($this->iriConverter->getResourceFromIri($this->restContext->resources['login_user'])) ->setCreatedAt(new \DateTime()) - ->setExpiresAt(new \DateTime($expiresAt)); + ->setExpiresAt(new \DateTimeImmutable($expiresAt)); $this->manager->persist($refreshToken); $this->manager->flush(); $this->restContext->resources['refresh_token'] = $refreshToken->getId(); diff --git a/src/Doctrine/Extension/ORM/PublishableExtension.php b/src/Doctrine/Extension/ORM/PublishableExtension.php index bae9a66e..655866ef 100644 --- a/src/Doctrine/Extension/ORM/PublishableExtension.php +++ b/src/Doctrine/Extension/ORM/PublishableExtension.php @@ -128,7 +128,7 @@ private function updateQueryBuilderForUnauthorizedUsers(QueryBuilder $queryBuild $queryBuilder ->andWhere("$alias.$configuration->fieldName IS NOT NULL") ->andWhere("$alias.$configuration->fieldName <= :currentTime") - ->setParameter('currentTime', new \DateTimeImmutable()); + ->setParameter('currentTime', new \DateTime()); } private function getConfiguration(string $resourceClass): ?Publishable diff --git a/src/EventListener/Doctrine/PublishableListener.php b/src/EventListener/Doctrine/PublishableListener.php index a5b52e24..42983d44 100644 --- a/src/EventListener/Doctrine/PublishableListener.php +++ b/src/EventListener/Doctrine/PublishableListener.php @@ -55,6 +55,7 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void } if (!$metadata->hasAssociation($configuration->associationName)) { + $referencedColumnName = $namingStrategy->referenceColumnName(); $metadata->mapOneToOne( [ 'fieldName' => $configuration->associationName, @@ -63,9 +64,9 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void [ 'name' => $namingStrategy->joinKeyColumnName( $configuration->associationName, - $metadata->getName() + $referencedColumnName ), - 'referencedColumnName' => $namingStrategy->referenceColumnName(), + 'referencedColumnName' => $referencedColumnName, 'onDelete' => 'SET NULL', 'nullable' => true, ], diff --git a/src/EventListener/Doctrine/TimestampedListener.php b/src/EventListener/Doctrine/TimestampedListener.php index 367f3e50..2c9f298b 100644 --- a/src/EventListener/Doctrine/TimestampedListener.php +++ b/src/EventListener/Doctrine/TimestampedListener.php @@ -36,7 +36,6 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void } $configuration = $this->annotationReader->getConfiguration($metadata->getName()); - if (!$metadata->hasField($configuration->createdAtField)) { $metadata->mapField( [ diff --git a/src/Filter/OrSearchFilter.php b/src/Filter/OrSearchFilter.php index d4ac4708..fb7730ca 100644 --- a/src/Filter/OrSearchFilter.php +++ b/src/Filter/OrSearchFilter.php @@ -57,7 +57,6 @@ public function __construct( protected function getType(string $doctrineType): string { return match ($doctrineType) { - Types::ARRAY => 'array', Types::JSON => 'json', Types::BIGINT, Types::INTEGER, Types::SMALLINT => 'int', Types::BOOLEAN => 'bool', diff --git a/src/Mercure/MercureResourcePublisher.php b/src/Mercure/MercureResourcePublisher.php index 79b5e866..fe89cb30 100644 --- a/src/Mercure/MercureResourcePublisher.php +++ b/src/Mercure/MercureResourcePublisher.php @@ -126,11 +126,11 @@ private function storeObjectToPublish(object $object, string $property): void $id = $this->iriConverter->getIriFromResource($object); $iri = $this->iriConverter->getIriFromResource($object, UrlGeneratorInterface::ABS_URL); - $objectData = ['id' => $id, 'iri' => $iri, 'mercureOptions' => $this->normalizeMercureOptions($options)]; + $objectData = ['id' => $id, 'iri' => $iri, 'mercureOptions' => $this->normalizeMercureOptions($options, $object)]; if ('deletedObjects' === $property) { - $this->createdObjects->detach($object); - $this->updatedObjects->detach($object); + $this->createdObjects->offsetUnset($object); + $this->updatedObjects->offsetUnset($object); $this->deletedObjects[$object] = $objectData; return; @@ -173,14 +173,14 @@ private function getObjectMercureOptions(object $object): ?array foreach ($options as $key => $value) { if (!isset(self::ALLOWED_KEYS[$key])) { - throw new InvalidArgumentException(\sprintf('The option "%s" set in the "mercure" attribute of the "%s" resource does not exist. Existing options: "%s"', $key, $resourceClass, implode('", "', self::ALLOWED_KEYS))); + throw new InvalidArgumentException(\sprintf('The option "%s" set in the "mercure" attribute of the "%s" resource does not exist. Existing options: "%s"', $key, $resourceClass, implode('", "', array_keys(self::ALLOWED_KEYS)))); } } return $options; } - private function normalizeMercureOptions(array $options): array + private function normalizeMercureOptions(array $options, object $object): array { $options['enable_async_update'] ??= true; @@ -192,11 +192,6 @@ private function normalizeMercureOptions(array $options): array continue; } - if (!str_starts_with($topic, '@=')) { - $topics[] = $topic; - continue; - } - if (null === $this->expressionLanguage) { throw new \LogicException('The "@=" expression syntax cannot be used without the Expression Language component. Try running "composer require symfony/expression-language".'); } @@ -229,7 +224,7 @@ public function propagate(): void } } - private function getObjectData(object $object, string $iri) + private function getObjectData(object $object, string $iri, array $options): string { $resourceClass = $this->getObjectClass($object); @@ -250,7 +245,9 @@ private function getObjectData(object $object, string $iri) private function publishUpdate(object $object, array $objectData, string $type): void { $options = $objectData['mercureOptions']; - $iri = $options['topics'] ?? $objectData['iri']; + + $topicIri = $options['topics'] ?? $objectData['iri']; + $resourceIri = $objectData['iri']; $getDeletedObjectData = static function () use ($objectData) { return json_encode(['@id' => $objectData['id']], \JSON_THROW_ON_ERROR); @@ -260,15 +257,17 @@ private function publishUpdate(object $object, array $objectData, string $type): $data = $getDeletedObjectData(); } else { try { - $data = $this->getObjectData($object, $iri); + $data = $this->getObjectData($object, $resourceIri, $options); } catch (InvalidArgumentException|LegacyInvalidArgumentException) { - // the object may have been deleted at the database level with delete cascades... $type = 'delete'; $data = $getDeletedObjectData(); } } - $updates = array_merge([$this->buildUpdate($iri, $data, $options)], $this->getGraphQlSubscriptionUpdates($object, $options, $type)); + $updates = array_merge( + [$this->buildUpdate($topicIri, $data, $options)], + $this->getGraphQlSubscriptionUpdates($object, $options, $type) + ); foreach ($updates as $update) { if ($options['enable_async_update'] && $this->messageBus) { diff --git a/src/RefreshToken/RefreshToken.php b/src/RefreshToken/RefreshToken.php index be51332d..5b7cf903 100644 --- a/src/RefreshToken/RefreshToken.php +++ b/src/RefreshToken/RefreshToken.php @@ -19,7 +19,7 @@ class RefreshToken { protected ?\DateTimeInterface $createdAt = null; - protected ?\DateTimeInterface $expiresAt = null; + protected ?\DateTimeImmutable $expiresAt = null; protected ?UserInterface $user = null; protected ?int $version = null; @@ -38,7 +38,7 @@ public function setCreatedAt(\DateTimeInterface $createdAt) return $this; } - public function getExpiresAt(): ?\DateTimeInterface + public function getExpiresAt(): ?\DateTimeImmutable { return $this->expiresAt; } @@ -46,7 +46,7 @@ public function getExpiresAt(): ?\DateTimeInterface /** * @return static */ - public function setExpiresAt(\DateTimeInterface $expiresAt) + public function setExpiresAt(\DateTimeImmutable $expiresAt) { $this->expiresAt = $expiresAt; diff --git a/src/Resources/config/doctrine-orm/Core.AbstractRefreshToken.orm.xml b/src/Resources/config/doctrine-orm/Core.AbstractRefreshToken.orm.xml index 8d8e4c28..baca3659 100644 --- a/src/Resources/config/doctrine-orm/Core.AbstractRefreshToken.orm.xml +++ b/src/Resources/config/doctrine-orm/Core.AbstractRefreshToken.orm.xml @@ -2,8 +2,8 @@ - - + + From 98ad0ee6a2685cd0dcf0d357e452bbc2e0c06e6a Mon Sep 17 00:00:00 2001 From: silverbackdan Date: Sun, 10 May 2026 11:07:41 +0100 Subject: [PATCH 3/4] More DTI fix --- features/bootstrap/DoctrineContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/DoctrineContext.php b/features/bootstrap/DoctrineContext.php index 8ca65725..5d52def9 100644 --- a/features/bootstrap/DoctrineContext.php +++ b/features/bootstrap/DoctrineContext.php @@ -884,7 +884,7 @@ public function iHaveARefreshToken(string $expiresAt = '+10 seconds'): void $refreshToken = new RefreshToken(); $refreshToken ->setUser($this->iriConverter->getResourceFromIri($this->restContext->resources['login_user'])) - ->setCreatedAt(new \DateTime()) + ->setCreatedAt(new \DateTimeImmutable()) ->setExpiresAt(new \DateTimeImmutable($expiresAt)); $this->manager->persist($refreshToken); $this->manager->flush(); From ee6b4009166813f4196483d6fce0aff78303dd35 Mon Sep 17 00:00:00 2001 From: silverbackdan Date: Sun, 10 May 2026 20:08:04 +0100 Subject: [PATCH 4/4] CS Fixes --- src/Doctrine/Extension/ORM/TablePrefixExtension.php | 2 +- .../TestBundle/Entity/DummyUploadableAndPublishable.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Doctrine/Extension/ORM/TablePrefixExtension.php b/src/Doctrine/Extension/ORM/TablePrefixExtension.php index 9e2f94c9..f95ccce9 100644 --- a/src/Doctrine/Extension/ORM/TablePrefixExtension.php +++ b/src/Doctrine/Extension/ORM/TablePrefixExtension.php @@ -65,7 +65,7 @@ private function setJoinTableName(ClassMetadata $classMetadata): void continue; } - if ($mapping->inherited !== null) { + if (null !== $mapping->inherited) { continue; } diff --git a/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php b/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php index fd22bc25..32c63fff 100644 --- a/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php +++ b/tests/Functional/TestBundle/Entity/DummyUploadableAndPublishable.php @@ -15,7 +15,6 @@ use Doctrine\ORM\Mapping as ORM; use Silverback\ApiComponentsBundle\Annotation as Silverback; use Silverback\ApiComponentsBundle\Entity\Core\AbstractComponent; -use Silverback\ApiComponentsBundle\Entity\Utility\IdTrait; use Silverback\ApiComponentsBundle\Entity\Utility\PublishableTrait; use Silverback\ApiComponentsBundle\Entity\Utility\UploadableTrait; use Symfony\Component\HttpFoundation\File\File;