Skip to content

Commit 2cee022

Browse files
[DoctrineBridge] Make EntityValueResolver::supports() more specific
1 parent fe865c2 commit 2cee022

File tree

2 files changed

+104
-78
lines changed

2 files changed

+104
-78
lines changed

ArgumentResolver/EntityValueResolver.php

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -47,37 +47,45 @@ public function supports(Request $request, ArgumentMetadata $argument): bool
4747
return false;
4848
}
4949

50-
$options = $this->getOptions($argument);
50+
$options = $this->getMapEntityAttribute($argument);
5151
if (!$options->class || $options->disabled) {
5252
return false;
5353
}
5454

55+
if (null === $options->expr && !($options->mapping || $options->exclude) && null === $this->getIdentifier($request, $options, $argument->getName())) {
56+
return false;
57+
}
58+
5559
// Doctrine Entity?
5660
if (!$objectManager = $this->getManager($options->objectManager, $options->class)) {
5761
return false;
5862
}
5963

60-
return !$objectManager->getMetadataFactory()->isTransient($options->class);
64+
if ($objectManager->getMetadataFactory()->isTransient($options->class)) {
65+
return false;
66+
}
67+
68+
return null !== $options->expr || $this->getCriteria($request, $options, $objectManager);
6169
}
6270

6371
/**
6472
* {@inheritdoc}
6573
*/
6674
public function resolve(Request $request, ArgumentMetadata $argument): iterable
6775
{
68-
$options = $this->getOptions($argument);
76+
$options = $this->getMapEntityAttribute($argument);
6977
$name = $argument->getName();
70-
$class = $options->class;
78+
$objectManager = $this->getManager($options->objectManager, $options->class);
7179

7280
$errorMessage = null;
7381
if (null !== $options->expr) {
74-
if (null === $object = $this->findViaExpression($class, $request, $options->expr, $options)) {
82+
if (null === $object = $this->findViaExpression($objectManager, $request, $options)) {
7583
$errorMessage = sprintf('The expression "%s" returned null', $options->expr);
7684
}
7785
// find by identifier?
78-
} elseif (false === $object = $this->find($class, $request, $options, $name)) {
86+
} elseif (false === $object = $this->find($objectManager, $request, $options, $name)) {
7987
// find by criteria
80-
if (false === $object = $this->findOneBy($class, $request, $options)) {
88+
if (false === $object = $this->findOneBy($objectManager, $request, $options)) {
8189
if (!$argument->isNullable()) {
8290
throw new \LogicException(sprintf('Unable to guess how to get a Doctrine instance from the request information for parameter "%s".', $name));
8391
}
@@ -87,7 +95,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable
8795
}
8896

8997
if (null === $object && !$argument->isNullable()) {
90-
$message = sprintf('"%s" object not found by the "%s" Argument Resolver.', $class, self::class);
98+
$message = sprintf('"%s" object not found by the "%s" Argument Resolver.', $options->class, self::class);
9199
if ($errorMessage) {
92100
$message .= ' '.$errorMessage;
93101
}
@@ -115,7 +123,7 @@ private function getManager(?string $name, string $class): ?ObjectManager
115123
}
116124
}
117125

118-
private function find(string $class, Request $request, MapEntity $options, string $name): false|object|null
126+
private function find(ObjectManager $objectManager, Request $request, MapEntity $options, string $name): false|object|null
119127
{
120128
if ($options->mapping || $options->exclude) {
121129
return false;
@@ -126,16 +134,15 @@ private function find(string $class, Request $request, MapEntity $options, strin
126134
return $id;
127135
}
128136

129-
$objectManager = $this->getManager($options->objectManager, $class);
130137
if ($options->evictCache && $objectManager instanceof EntityManagerInterface) {
131138
$cacheProvider = $objectManager->getCache();
132-
if ($cacheProvider && $cacheProvider->containsEntity($class, $id)) {
133-
$cacheProvider->evictEntity($class, $id);
139+
if ($cacheProvider && $cacheProvider->containsEntity($options->class, $id)) {
140+
$cacheProvider->evictEntity($options->class, $id);
134141
}
135142
}
136143

137144
try {
138-
return $objectManager->getRepository($class)->find($id);
145+
return $objectManager->getRepository($options->class)->find($id);
139146
} catch (NoResultException|ConversionException) {
140147
return null;
141148
}
@@ -162,40 +169,55 @@ private function getIdentifier(Request $request, MapEntity $options, string $nam
162169
}
163170

164171
if ($request->attributes->has($name)) {
165-
return $request->attributes->get($name);
172+
return $request->attributes->get($name) ?? ($options->stripNull ? false : null);
166173
}
167174

168175
if (!$options->id && $request->attributes->has('id')) {
169-
return $request->attributes->get('id');
176+
return $request->attributes->get('id') ?? ($options->stripNull ? false : null);
170177
}
171178

172179
return false;
173180
}
174181

175-
private function findOneBy(string $class, Request $request, MapEntity $options): false|object|null
182+
private function findOneBy(ObjectManager $objectManager, Request $request, MapEntity $options): false|object|null
183+
{
184+
if (!$criteria = $this->getCriteria($request, $options, $objectManager)) {
185+
return false;
186+
}
187+
188+
try {
189+
return $objectManager->getRepository($options->class)->findOneBy($criteria);
190+
} catch (NoResultException|ConversionException) {
191+
return null;
192+
}
193+
}
194+
195+
private function getCriteria(Request $request, MapEntity $options, ObjectManager $objectManager): array
176196
{
177197
if (null === $mapping = $options->mapping) {
178-
$keys = $request->attributes->keys();
179-
$mapping = $keys ? array_combine($keys, $keys) : [];
198+
$mapping = $request->attributes->keys();
199+
}
200+
201+
if ($mapping && \is_array($mapping) && array_is_list($mapping)) {
202+
$mapping = array_combine($mapping, $mapping);
180203
}
181204

182205
foreach ($options->exclude as $exclude) {
183206
unset($mapping[$exclude]);
184207
}
185208

186209
if (!$mapping) {
187-
return false;
210+
return [];
188211
}
189212

190213
// if a specific id has been defined in the options and there is no corresponding attribute
191214
// return false in order to avoid a fallback to the id which might be of another object
192215
if (\is_string($options->id) && null === $request->attributes->get($options->id)) {
193-
return false;
216+
return [];
194217
}
195218

196219
$criteria = [];
197-
$objectManager = $this->getManager($options->objectManager, $class);
198-
$metadata = $objectManager->getClassMetadata($class);
220+
$metadata = $objectManager->getClassMetadata($options->class);
199221

200222
foreach ($mapping as $attribute => $field) {
201223
if (!$metadata->hasField($field) && (!$metadata->hasAssociation($field) || !$metadata->isSingleValuedAssociation($field))) {
@@ -209,34 +231,26 @@ private function findOneBy(string $class, Request $request, MapEntity $options):
209231
$criteria = array_filter($criteria, static fn ($value) => null !== $value);
210232
}
211233

212-
if (!$criteria) {
213-
return false;
214-
}
215-
216-
try {
217-
return $objectManager->getRepository($class)->findOneBy($criteria);
218-
} catch (NoResultException|ConversionException) {
219-
return null;
220-
}
234+
return $criteria;
221235
}
222236

223-
private function findViaExpression(string $class, Request $request, string $expression, MapEntity $options): ?object
237+
private function findViaExpression(ObjectManager $objectManager, Request $request, MapEntity $options): ?object
224238
{
225239
if (!$this->expressionLanguage) {
226240
throw new \LogicException(sprintf('You cannot use the "%s" if the ExpressionLanguage component is not available. Try running "composer require symfony/expression-language".', __CLASS__));
227241
}
228242

229-
$repository = $this->getManager($options->objectManager, $class)->getRepository($class);
243+
$repository = $objectManager->getRepository($options->class);
230244
$variables = array_merge($request->attributes->all(), ['repository' => $repository]);
231245

232246
try {
233-
return $this->expressionLanguage->evaluate($expression, $variables);
247+
return $this->expressionLanguage->evaluate($options->expr, $variables);
234248
} catch (NoResultException|ConversionException) {
235249
return null;
236250
}
237251
}
238252

239-
private function getOptions(ArgumentMetadata $argument): MapEntity
253+
private function getMapEntityAttribute(ArgumentMetadata $argument): MapEntity
240254
{
241255
/** @var MapEntity $options */
242256
$options = $argument->getAttributes(MapEntity::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? $this->defaults;

0 commit comments

Comments
 (0)