diff --git a/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php b/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php
index 3b3c5ca7a00..b71b807f39b 100644
--- a/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php
+++ b/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php
@@ -44,13 +44,17 @@ final class EagerLoadingExtension implements QueryCollectionExtensionInterface,
private $serializerContextBuilder;
private $requestStack;
- public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, int $maxJoins = 30, bool $forceEager = true, RequestStack $requestStack = null, SerializerContextBuilderInterface $serializerContextBuilder = null)
+ /**
+ * @TODO move $fetchPartial after $forceEager (@soyuka) in 3.0
+ */
+ public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, int $maxJoins = 30, bool $forceEager = true, RequestStack $requestStack = null, SerializerContextBuilderInterface $serializerContextBuilder = null, bool $fetchPartial = false)
{
$this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
$this->propertyMetadataFactory = $propertyMetadataFactory;
$this->resourceMetadataFactory = $resourceMetadataFactory;
$this->maxJoins = $maxJoins;
$this->forceEager = $forceEager;
+ $this->fetchPartial = $fetchPartial;
$this->serializerContextBuilder = $serializerContextBuilder;
$this->requestStack = $requestStack;
}
@@ -67,10 +71,11 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator
}
$forceEager = $this->shouldOperationForceEager($resourceClass, $options);
+ $fetchPartial = $this->shouldOperationFetchPartial($resourceClass, $options);
$groups = $this->getSerializerGroups($resourceClass, $options, 'normalization_context');
- $this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $queryBuilder->getRootAliases()[0], $groups);
+ $this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $fetchPartial, $queryBuilder->getRootAliases()[0], $groups);
}
/**
@@ -86,6 +91,7 @@ public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterf
}
$forceEager = $this->shouldOperationForceEager($resourceClass, $options);
+ $fetchPartial = $this->shouldOperationFetchPartial($resourceClass, $options);
if (isset($context['groups'])) {
$groups = ['serializer_groups' => $context['groups']];
@@ -95,7 +101,7 @@ public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterf
$groups = $this->getSerializerGroups($resourceClass, $options, 'normalization_context');
}
- $this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $queryBuilder->getRootAliases()[0], $groups);
+ $this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $fetchPartial, $queryBuilder->getRootAliases()[0], $groups);
}
/**
@@ -112,7 +118,7 @@ public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterf
*
* @throws RuntimeException when the max number of joins has been reached
*/
- private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, bool $forceEager, string $parentAlias, array $propertyMetadataOptions = [], bool $wasLeftJoin = false, int &$joinCount = 0)
+ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, bool $forceEager, bool $fetchPartial, string $parentAlias, array $propertyMetadataOptions = [], bool $wasLeftJoin = false, int &$joinCount = 0)
{
if ($joinCount > $this->maxJoins) {
throw new RuntimeException('The total number of joined relations has exceeded the specified maximum. Raise the limit if necessary.');
@@ -152,18 +158,23 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt
$queryBuilder->{$method}(sprintf('%s.%s', $parentAlias, $association), $associationAlias);
++$joinCount;
- try {
- $this->addSelect($queryBuilder, $mapping['targetEntity'], $associationAlias, $propertyMetadataOptions);
- } catch (ResourceClassNotFoundException $resourceClassNotFoundException) {
- continue;
+ if (true === $fetchPartial) {
+ try {
+ $this->addSelect($queryBuilder, $mapping['targetEntity'], $associationAlias, $propertyMetadataOptions);
+ } catch (ResourceClassNotFoundException $resourceClassNotFoundException) {
+ continue;
+ }
+ } else {
+ $queryBuilder->addSelect($associationAlias);
}
+ // Avoid recursion
if ($mapping['targetEntity'] === $resourceClass) {
$queryBuilder->addSelect($associationAlias);
continue;
}
- $this->joinRelations($queryBuilder, $queryNameGenerator, $mapping['targetEntity'], $forceEager, $associationAlias, $propertyMetadataOptions, $method === 'leftJoin', $joinCount);
+ $this->joinRelations($queryBuilder, $queryNameGenerator, $mapping['targetEntity'], $forceEager, $fetchPartial, $associationAlias, $propertyMetadataOptions, $method === 'leftJoin', $joinCount);
}
}
@@ -184,7 +195,7 @@ private function addSelect(QueryBuilder $queryBuilder, string $entity, string $a
}
//the field test allows to add methods to a Resource which do not reflect real database fields
- if (true === $targetClassMetadata->hasField($property) && true === $propertyMetadata->isReadable()) {
+ if (true === $targetClassMetadata->hasField($property) && (true === $propertyMetadata->getAttribute('fetchable') || true === $propertyMetadata->isReadable())) {
$select[] = $property;
}
}
diff --git a/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php b/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php
index 712ca921d71..d9aed58b920 100644
--- a/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php
+++ b/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php
@@ -24,6 +24,7 @@
trait EagerLoadingTrait
{
private $forceEager;
+ private $fetchPartial;
private $resourceMetadataFactory;
/**
@@ -35,18 +36,46 @@ trait EagerLoadingTrait
* @return bool
*/
private function shouldOperationForceEager(string $resourceClass, array $options): bool
+ {
+ return $this->getBooleanOperationAttribute($resourceClass, $options, 'force_eager', $this->forceEager);
+ }
+
+ /**
+ * Checks if an operation has a `fetch_partial` attribute.
+ *
+ * @param string $resourceClass
+ * @param array $options
+ *
+ * @return bool
+ */
+ private function shouldOperationFetchPartial(string $resourceClass, array $options): bool
+ {
+ return $this->getBooleanOperationAttribute($resourceClass, $options, 'fetch_partial', $this->fetchPartial);
+ }
+
+ /**
+ * Get the boolean attribute of an operation or the resource metadata.
+ *
+ * @param string $resourceClass
+ * @param array $options
+ * @param string $attributeName
+ * @param bool $default
+ *
+ * @return bool
+ */
+ private function getBooleanOperationAttribute(string $resourceClass, array $options, string $attributeName, bool $default): bool
{
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
if (isset($options['collection_operation_name'])) {
- $forceEager = $resourceMetadata->getCollectionOperationAttribute($options['collection_operation_name'], 'force_eager', null, true);
+ $attribute = $resourceMetadata->getCollectionOperationAttribute($options['collection_operation_name'], $attributeName, null, true);
} elseif (isset($options['item_operation_name'])) {
- $forceEager = $resourceMetadata->getItemOperationAttribute($options['item_operation_name'], 'force_eager', null, true);
+ $attribute = $resourceMetadata->getItemOperationAttribute($options['item_operation_name'], $attributeName, null, true);
} else {
- $forceEager = $resourceMetadata->getAttribute('force_eager');
+ $attribute = $resourceMetadata->getAttribute($attributeName);
}
- return is_bool($forceEager) ? $forceEager : (bool) $this->forceEager;
+ return is_bool($attribute) ? $attribute : $default;
}
/**
diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
index 597b4fe78b7..b33c021bbc0 100644
--- a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
+++ b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
@@ -110,6 +110,7 @@ private function handleConfig(ContainerBuilder $container, array $config, array
$container->setParameter('api_platform.error_formats', $errorFormats);
$container->setParameter('api_platform.eager_loading.enabled', $config['eager_loading']['enabled']);
$container->setParameter('api_platform.eager_loading.max_joins', $config['eager_loading']['max_joins']);
+ $container->setParameter('api_platform.eager_loading.fetch_partial', $config['eager_loading']['fetch_partial']);
$container->setParameter('api_platform.eager_loading.force_eager', $config['eager_loading']['force_eager']);
$container->setParameter('api_platform.collection.order', $config['collection']['order']);
$container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']);
diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
index 1e7f75171d3..cafae3f45a5 100644
--- a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
+++ b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
@@ -50,6 +50,7 @@ public function getConfigTreeBuilder()
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultTrue()->info('To enable or disable eager loading')->end()
+ ->booleanNode('fetch_partial')->defaultFalse()->info('Fetch only partial data according to serialization groups. If enabled, Doctrine ORM entities will not work as expected if any of the other fields are used.')->end()
->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
->end()
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml b/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
index d0d35530196..4f2004868e6 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml
@@ -95,6 +95,7 @@
%api_platform.eager_loading.force_eager%
+ %api_platform.eager_loading.fetch_partial%
diff --git a/src/Metadata/Property/PropertyMetadata.php b/src/Metadata/Property/PropertyMetadata.php
index 79ecebaee58..3e5794ba089 100644
--- a/src/Metadata/Property/PropertyMetadata.php
+++ b/src/Metadata/Property/PropertyMetadata.php
@@ -288,6 +288,23 @@ public function getAttributes()
return $this->attributes;
}
+ /**
+ * Gets an attribute.
+ *
+ * @param string $key
+ * @param mixed $defaultValue
+ *
+ * @return mixed
+ */
+ public function getAttribute(string $key, $defaultValue = null)
+ {
+ if (isset($this->attributes[$key])) {
+ return $this->attributes[$key];
+ }
+
+ return $defaultValue;
+ }
+
/**
* Returns a new instance with the given attribute.
*
diff --git a/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php b/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php
index 26f2344c5f5..087bd024db5 100644
--- a/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php
+++ b/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php
@@ -105,7 +105,7 @@ public function testApplyToCollection()
$queryBuilderProphecy->addSelect('partial relatedDummy2_a2.{id,name}')->shouldBeCalled(1);
$queryBuilder = $queryBuilderProphecy->reveal();
- $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$eagerExtensionTest->applyToCollection($queryBuilder, new QueryNameGenerator(), Dummy::class);
}
@@ -200,7 +200,7 @@ public function testApplyToItem()
$queryBuilderProphecy->addSelect('singleInheritanceRelation_a6')->shouldBeCalled(1);
$queryBuilder = $queryBuilderProphecy->reveal();
- $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$orderExtensionTest->applyToItem($queryBuilder, new QueryNameGenerator(), Dummy::class, []);
}
@@ -225,7 +225,7 @@ public function testCreateItemWithOperationName()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, [], 'item_operation');
}
@@ -249,7 +249,7 @@ public function testCreateCollectionWithOperationName()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$eagerExtensionTest->applyToCollection($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, 'collection_operation');
}
@@ -271,7 +271,7 @@ public function testDenormalizeItemWithCorrectResourceClass()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', ['resource_class' => Dummy::class]);
}
@@ -293,7 +293,7 @@ public function testDenormalizeItemWithExistingGroups()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', ['groups' => 'some_groups']);
}
@@ -346,7 +346,7 @@ public function testMaxDepthReached()
$queryBuilderProphecy->innerJoin(Argument::type('string'), Argument::type('string'))->shouldBeCalled();
$queryBuilderProphecy->addSelect(Argument::type('string'))->shouldBeCalled();
- $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
$eagerExtensionTest->applyToCollection($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class);
}
@@ -390,7 +390,7 @@ public function testForceEager()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true);
+ $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
}
@@ -414,7 +414,7 @@ public function testResourceClassNotFoundException()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true);
+ $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
}
@@ -438,7 +438,7 @@ public function testPropertyNotFoundException()
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
- $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true);
+ $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
}
@@ -467,7 +467,7 @@ public function testResourceClassNotFoundExceptionPropertyNameCollection()
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
$queryBuilderProphecy->innerJoin('o.relation', 'relation_a1')->shouldBeCalled(1);
- $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true);
+ $orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
}
@@ -531,7 +531,50 @@ public function testApplyToCollectionWithSerializerContextBuilder()
$serializerContextBuilderProphecy->createFromRequest($request, true)->shouldBeCalled()->willReturn(['groups' => ['foo']]);
$queryBuilder = $queryBuilderProphecy->reveal();
- $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, $requestStack, $serializerContextBuilderProphecy->reveal());
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, $requestStack, $serializerContextBuilderProphecy->reveal(), true);
+ $eagerExtensionTest->applyToCollection($queryBuilder, new QueryNameGenerator(), Dummy::class);
+ }
+
+ public function testApplyToCollectionNoPartial()
+ {
+ $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
+ $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata());
+
+ $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
+
+ $relatedNameCollection = new PropertyNameCollection(['id', 'name', 'notindatabase', 'notreadable']);
+
+ $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
+ $relationPropertyMetadata = new PropertyMetadata();
+ $relationPropertyMetadata = $relationPropertyMetadata->withReadableLink(true);
+
+ $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn($relationPropertyMetadata)->shouldBeCalled();
+ $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy2', [])->willReturn($relationPropertyMetadata)->shouldBeCalled();
+
+ $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
+
+ $classMetadataProphecy = $this->prophesize(ClassMetadata::class);
+ $classMetadataProphecy->associationMappings = [
+ 'relatedDummy' => ['fetch' => 3, 'joinColumns' => [['nullable' => true]], 'targetEntity' => RelatedDummy::class],
+ 'relatedDummy2' => ['fetch' => 3, 'joinColumns' => [['nullable' => false]], 'targetEntity' => RelatedDummy::class],
+ ];
+
+ $emProphecy = $this->prophesize(EntityManager::class);
+ $relatedClassMetadataProphecy = $this->prophesize(ClassMetadata::class);
+ $relatedClassMetadataProphecy->associationMappings = [];
+ $emProphecy->getClassMetadata(Dummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
+ $emProphecy->getClassMetadata(RelatedDummy::class)->shouldBeCalled()->willReturn($relatedClassMetadataProphecy->reveal());
+
+ $queryBuilderProphecy->getRootAliases()->willReturn(['o']);
+ $queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
+
+ $queryBuilderProphecy->leftJoin('o.relatedDummy', 'relatedDummy_a1')->shouldBeCalled(1);
+ $queryBuilderProphecy->innerJoin('o.relatedDummy2', 'relatedDummy2_a2')->shouldBeCalled(1);
+ $queryBuilderProphecy->addSelect('relatedDummy_a1')->shouldBeCalled(1);
+ $queryBuilderProphecy->addSelect('relatedDummy2_a2')->shouldBeCalled(1);
+
+ $queryBuilder = $queryBuilderProphecy->reveal();
+ $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30);
$eagerExtensionTest->applyToCollection($queryBuilder, new QueryNameGenerator(), Dummy::class);
}
}
diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
index 5d1384c2edf..d25c9a52efc 100644
--- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
+++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php
@@ -231,6 +231,7 @@ private function getContainerBuilderProphecy()
'api_platform.eager_loading.enabled' => Argument::type('bool'),
'api_platform.eager_loading.max_joins' => 30,
'api_platform.eager_loading.force_eager' => true,
+ 'api_platform.eager_loading.fetch_partial' => false,
'api_platform.resource_class_directories' => [],
];
foreach ($parameters as $key => $value) {
diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
index ccf33a7f855..b0b66932f3a 100644
--- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
+++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php
@@ -77,6 +77,7 @@ public function testDefaultConfig()
'enabled' => true,
'max_joins' => 30,
'force_eager' => true,
+ 'fetch_partial' => false,
],
'collection' => [
'order' => null,
diff --git a/tests/Metadata/Property/PropertyMetadataTest.php b/tests/Metadata/Property/PropertyMetadataTest.php
index 8b34768ac22..b34605c0e67 100644
--- a/tests/Metadata/Property/PropertyMetadataTest.php
+++ b/tests/Metadata/Property/PropertyMetadataTest.php
@@ -76,6 +76,7 @@ public function testValueObject()
$newMetadata = $metadata->withAttributes(['a' => 'b']);
$this->assertNotSame($metadata, $newMetadata);
$this->assertEquals(['a' => 'b'], $newMetadata->getAttributes());
+ $this->assertEquals('b', $newMetadata->getAttribute('a'));
}
public function testShouldReturnRequiredFalseWhenRequiredTrueIsSetButMaskedByWritableFalse()