Skip to content

Commit ccb844f

Browse files
michaelKaeferjaviereguiluz
authored andcommitted
Refactor EntityDto: deprecate 3 methods and allow access to ClassMetadata instead
1 parent c5ad03a commit ccb844f

File tree

12 files changed

+167
-42
lines changed

12 files changed

+167
-42
lines changed

src/Dto/EntityDto.php

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public function getAllPropertyNames(): array
181181

182182
public function getPropertyMetadata(string $propertyName): KeyValueStore
183183
{
184-
if (\array_key_exists($propertyName, $this->metadata->fieldMappings)) {
184+
if (isset($this->metadata->fieldMappings[$propertyName])) {
185185
/** @var FieldMapping|array $fieldMapping */
186186
/** @phpstan-ignore-next-line */
187187
$fieldMapping = $this->metadata->fieldMappings[$propertyName];
@@ -194,7 +194,7 @@ public function getPropertyMetadata(string $propertyName): KeyValueStore
194194
return KeyValueStore::new($fieldMapping);
195195
}
196196

197-
if (\array_key_exists($propertyName, $this->metadata->associationMappings)) {
197+
if ($this->metadata->hasAssociation($propertyName)) {
198198
/** @var AssociationMapping|array $associationMapping */
199199
/** @phpstan-ignore-next-line */
200200
$associationMapping = $this->metadata->associationMappings[$propertyName];
@@ -215,42 +215,52 @@ public function getPropertyMetadata(string $propertyName): KeyValueStore
215215
throw new \InvalidArgumentException(sprintf('The "%s" field does not exist in the "%s" entity.', $propertyName, $this->getFqcn()));
216216
}
217217

218+
public function getClassMetadata(): ClassMetadata
219+
{
220+
return $this->metadata;
221+
}
222+
223+
/**
224+
* @deprecated since 4.27 and to be removed in 5.0, use $entityDto->getClassMetadata()->getFieldMapping($propertyName)->type and $entityDto->getClassMetadata()->getAssociationMapping($propertyName)->type() instead
225+
*/
218226
public function getPropertyDataType(string $propertyName): string|int
219227
{
220228
return $this->getPropertyMetadata($propertyName)->get('type');
221229
}
222230

223231
public function hasProperty(string $propertyName): bool
224232
{
225-
return \array_key_exists($propertyName, $this->metadata->fieldMappings)
226-
|| \array_key_exists($propertyName, $this->metadata->associationMappings);
233+
return isset($this->metadata->fieldMappings[$propertyName])
234+
|| $this->metadata->hasAssociation($propertyName);
227235
}
228236

229237
public function isAssociation(string $propertyName): bool
230238
{
231-
return \array_key_exists($propertyName, $this->metadata->associationMappings)
239+
return $this->metadata->hasAssociation($propertyName)
232240
|| (str_contains($propertyName, '.') && !$this->isEmbeddedClassProperty($propertyName));
233241
}
234242

243+
/**
244+
* @deprecated since 4.27 and to be removed in 5.0, use $entityDto->getClassMetadata()->isSingleValuedAssociation($propertyName)
245+
*/
235246
public function isToOneAssociation(string $propertyName): bool
236247
{
237-
$associationType = $this->getPropertyDataType($propertyName);
238-
239-
return \in_array($associationType, [ClassMetadata::ONE_TO_ONE, ClassMetadata::MANY_TO_ONE], true);
248+
return $this->getClassMetadata()->isSingleValuedAssociation($propertyName);
240249
}
241250

251+
/**
252+
* @deprecated since 4.27 and to be removed in 5.0, use $entityDto->getClassMetadata()->isCollectionValuedAssociation($propertyName)
253+
*/
242254
public function isToManyAssociation(string $propertyName): bool
243255
{
244-
$associationType = $this->getPropertyDataType($propertyName);
245-
246-
return \in_array($associationType, [ClassMetadata::ONE_TO_MANY, ClassMetadata::MANY_TO_MANY], true);
256+
return $this->getClassMetadata()->isCollectionValuedAssociation($propertyName);
247257
}
248258

249259
public function isEmbeddedClassProperty(string $propertyName): bool
250260
{
251261
$propertyNameParts = explode('.', $propertyName, 2);
252262

253-
return \array_key_exists($propertyNameParts[0], $this->metadata->embeddedClasses);
263+
return isset($this->metadata->embeddedClasses[$propertyNameParts[0]]);
254264
}
255265

256266
/**

src/Factory/FieldFactory.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Doctrine\DBAL\Types\Types;
66
use Doctrine\ORM\Mapping\AssociationMapping;
7+
use Doctrine\ORM\Mapping\FieldMapping;
78
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
89
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
910
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldConfiguratorInterface;
@@ -160,12 +161,23 @@ private function replaceGenericFieldsWithSpecificFields(FieldCollection $fields,
160161
} else {
161162
$guessedFieldFqcn = AssociationField::class;
162163
}
164+
} elseif (!isset($entityDto->getClassMetadata()->fieldMappings[$fieldDto->getProperty()])) {
165+
throw new \RuntimeException(sprintf('Could not guess a field class for "%s" field. It possibly is an association field or an embedded class field.', $fieldDto->getProperty()));
163166
} else {
164-
$doctrinePropertyType = $entityDto->getPropertyDataType($fieldDto->getProperty());
165-
$guessedFieldFqcn = self::$doctrineTypeToFieldFqcn[$doctrinePropertyType] ?? null;
167+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
168+
/** @var FieldMapping|array $fieldMapping */
169+
/** @phpstan-ignore-next-line */
170+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($fieldDto->getProperty());
171+
if (\is_array($fieldMapping)) {
172+
$doctrineFieldMappingType = $fieldMapping['type'];
173+
} else {
174+
$doctrineFieldMappingType = $fieldMapping->type;
175+
}
176+
177+
$guessedFieldFqcn = self::$doctrineTypeToFieldFqcn[$doctrineFieldMappingType] ?? null;
166178

167179
if (null === $guessedFieldFqcn) {
168-
throw new \RuntimeException(sprintf('The Doctrine type of the "%s" field is "%s", which is not supported by EasyAdmin. For Doctrine\'s Custom Mapping Types have a look at EasyAdmin\'s field docs.', $fieldDto->getProperty(), $doctrinePropertyType));
180+
throw new \RuntimeException(sprintf('The Doctrine type of the "%s" field is "%s", which is not supported by EasyAdmin. For Doctrine\'s Custom Mapping Types have a look at EasyAdmin\'s field docs.', $fieldDto->getProperty(), $doctrineFieldMappingType));
169181
}
170182
}
171183

src/Factory/FilterFactory.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\Factory;
44

55
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\FieldMapping;
67
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
78
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
89
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterConfiguratorInterface;
@@ -99,6 +100,20 @@ private function guessFilterClass(EntityDto $entityDto, string $propertyName): s
99100
return EntityFilter::class;
100101
}
101102

102-
return self::$doctrineTypeToFilterClass[$entityDto->getPropertyDataType($propertyName)] ?? TextFilter::class;
103+
if (isset($entityDto->getClassMetadata()->embeddedClasses[$propertyName])) {
104+
return TextFilter::class;
105+
}
106+
107+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
108+
/** @var FieldMapping|array $fieldMapping */
109+
/** @phpstan-ignore-next-line */
110+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($propertyName);
111+
if (\is_array($fieldMapping)) {
112+
$doctrineFieldMappingType = $fieldMapping['type'];
113+
} else {
114+
$doctrineFieldMappingType = $fieldMapping->type;
115+
}
116+
117+
return self::$doctrineTypeToFilterClass[$doctrineFieldMappingType] ?? TextFilter::class;
103118
}
104119
}

src/Field/Configurator/AssociationConfigurator.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $c
5656
?? $context->getCrudControllers()->findCrudFqcnByEntityFqcn($targetEntityFqcn);
5757

5858
if (true === $field->getCustomOption(AssociationField::OPTION_RENDER_AS_EMBEDDED_FORM)) {
59-
if (false === $entityDto->isToOneAssociation($propertyName)) {
59+
if (false === $entityDto->getClassMetadata()->isSingleValuedAssociation($propertyName)) {
6060
throw new \RuntimeException(
6161
sprintf(
6262
'The "%s" association field of "%s" is a to-many association but it\'s trying to use the "renderAsEmbeddedForm()" option, which is only available for to-one associations. If you want to use a CRUD form to render to-many associations, use a CollectionField instead of the AssociationField.',
@@ -130,11 +130,11 @@ public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $c
130130
// * the route is not found, which happens when the associated entity is not accessible from this dashboard; do nothing in that case either.
131131
}
132132
} else {
133-
if ($entityDto->isToOneAssociation($propertyName)) {
133+
if ($entityDto->getClassMetadata()->isSingleValuedAssociation($propertyName)) {
134134
$this->configureToOneAssociation($field);
135135
}
136136

137-
if ($entityDto->isToManyAssociation($propertyName)) {
137+
if ($entityDto->getClassMetadata()->isCollectionValuedAssociation($propertyName)) {
138138
$this->configureToManyAssociation($field);
139139
}
140140
}

src/Field/Configurator/DateTimeConfigurator.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\Field\Configurator;
44

55
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\FieldMapping;
67
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
78
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldConfiguratorInterface;
89
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Intl\IntlFormatterInterface;
@@ -91,11 +92,21 @@ public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $c
9192
$field->setFormattedValue($formattedValue);
9293

9394
// check if the property is immutable, but only if it's a real Doctrine entity property
94-
if (!$entityDto->hasProperty($field->getProperty())) {
95+
if (!isset($entityDto->getClassMetadata()->fieldMappings[$field->getProperty()])) {
9596
return;
9697
}
97-
$doctrineDataType = $entityDto->getPropertyDataType($field->getProperty());
98-
$isImmutableDateTime = \in_array($doctrineDataType, [Types::DATETIMETZ_IMMUTABLE, Types::DATETIME_IMMUTABLE, Types::DATE_IMMUTABLE, Types::TIME_IMMUTABLE], true);
98+
99+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
100+
/** @var FieldMapping|array $fieldMapping */
101+
/** @phpstan-ignore-next-line */
102+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($field->getProperty());
103+
if (\is_array($fieldMapping)) {
104+
$doctrineFieldMappingType = $fieldMapping['type'];
105+
} else {
106+
$doctrineFieldMappingType = $fieldMapping->type;
107+
}
108+
109+
$isImmutableDateTime = \in_array($doctrineFieldMappingType, [Types::DATETIMETZ_IMMUTABLE, Types::DATETIME_IMMUTABLE, Types::DATE_IMMUTABLE, Types::TIME_IMMUTABLE], true);
99110
if ($isImmutableDateTime) {
100111
$field->setFormTypeOptionIfNotSet('input', 'datetime_immutable');
101112
}

src/Filter/Configurator/ComparisonConfigurator.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\Filter\Configurator;
44

55
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\FieldMapping;
67
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
78
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterConfiguratorInterface;
89
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
@@ -24,9 +25,21 @@ public function supports(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $e
2425

2526
public function configure(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $entityDto, AdminContext $context): void
2627
{
27-
$propertyType = $entityDto->getPropertyDataType($filterDto->getProperty());
28+
if (!isset($entityDto->getClassMetadata()->fieldMappings[$filterDto->getProperty()])) {
29+
return;
30+
}
31+
32+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
33+
/** @var FieldMapping|array $fieldMapping */
34+
/** @phpstan-ignore-next-line */
35+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($filterDto->getProperty());
36+
if (\is_array($fieldMapping)) {
37+
$doctrineFieldMappingType = $fieldMapping['type'];
38+
} else {
39+
$doctrineFieldMappingType = $fieldMapping->type;
40+
}
2841

29-
if (Types::DATEINTERVAL === $propertyType) {
42+
if (Types::DATEINTERVAL === $doctrineFieldMappingType) {
3043
$filterDto->setFormTypeOption('value_type', DateIntervalType::class);
3144
$filterDto->setFormTypeOption('comparison_type_options.type', 'datetime');
3245
}

src/Filter/Configurator/DateTimeConfigurator.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\Filter\Configurator;
44

55
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\FieldMapping;
67
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
78
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterConfiguratorInterface;
89
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
@@ -25,27 +26,39 @@ public function supports(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $e
2526

2627
public function configure(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $entityDto, AdminContext $context): void
2728
{
28-
$propertyType = $entityDto->getPropertyDataType($filterDto->getProperty());
29+
if (!isset($entityDto->getClassMetadata()->fieldMappings[$filterDto->getProperty()])) {
30+
return;
31+
}
32+
33+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
34+
/** @var FieldMapping|array $fieldMapping */
35+
/** @phpstan-ignore-next-line */
36+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($filterDto->getProperty());
37+
if (\is_array($fieldMapping)) {
38+
$doctrineFieldMappingType = $fieldMapping['type'];
39+
} else {
40+
$doctrineFieldMappingType = $fieldMapping->type;
41+
}
2942

30-
if (Types::DATE_MUTABLE === $propertyType) {
43+
if (Types::DATE_MUTABLE === $doctrineFieldMappingType) {
3144
$filterDto->setFormTypeOptionIfNotSet('value_type', DateType::class);
3245
}
3346

34-
if (Types::DATE_IMMUTABLE === $propertyType) {
47+
if (Types::DATE_IMMUTABLE === $doctrineFieldMappingType) {
3548
$filterDto->setFormTypeOptionIfNotSet('value_type', DateType::class);
3649
$filterDto->setFormTypeOptionIfNotSet('value_type_options.input', 'datetime_immutable');
3750
}
3851

39-
if (Types::TIME_MUTABLE === $propertyType) {
52+
if (Types::TIME_MUTABLE === $doctrineFieldMappingType) {
4053
$filterDto->setFormTypeOptionIfNotSet('value_type', TimeType::class);
4154
}
4255

43-
if (Types::TIME_IMMUTABLE === $propertyType) {
56+
if (Types::TIME_IMMUTABLE === $doctrineFieldMappingType) {
4457
$filterDto->setFormTypeOptionIfNotSet('value_type', TimeType::class);
4558
$filterDto->setFormTypeOptionIfNotSet('value_type_options.input', 'datetime_immutable');
4659
}
4760

48-
if (\in_array($propertyType, [Types::DATETIME_IMMUTABLE, Types::DATETIMETZ_IMMUTABLE], true)) {
61+
if (\in_array($doctrineFieldMappingType, [Types::DATETIME_IMMUTABLE, Types::DATETIMETZ_IMMUTABLE], true)) {
4962
$filterDto->setFormTypeOptionIfNotSet('value_type_options.input', 'datetime_immutable');
5063
}
5164
}

src/Filter/Configurator/EntityConfigurator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ public function configure(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $
3131
$doctrineMetadata = $entityDto->getPropertyMetadata($propertyName);
3232
// TODO: add the 'em' form type option too?
3333
$filterDto->setFormTypeOptionIfNotSet('value_type_options.class', $doctrineMetadata->get('targetEntity'));
34-
$filterDto->setFormTypeOptionIfNotSet('value_type_options.multiple', $entityDto->isToManyAssociation($propertyName));
34+
$filterDto->setFormTypeOptionIfNotSet('value_type_options.multiple', $entityDto->getClassMetadata()->isCollectionValuedAssociation($propertyName));
3535
$filterDto->setFormTypeOptionIfNotSet('value_type_options.attr.data-ea-widget', 'ea-autocomplete');
3636

37-
if ($entityDto->isToOneAssociation($propertyName)) {
37+
if ($entityDto->getClassMetadata()->isSingleValuedAssociation($propertyName)) {
3838
// don't show the 'empty value' placeholder when all join columns are required,
3939
// because an empty filter value would always return no result
4040
$numberOfRequiredJoinColumns = \count(array_filter(

src/Filter/Configurator/NumericConfigurator.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\Filter\Configurator;
44

55
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\FieldMapping;
67
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
78
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterConfiguratorInterface;
89
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
@@ -24,13 +25,25 @@ public function supports(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $e
2425

2526
public function configure(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $entityDto, AdminContext $context): void
2627
{
27-
$propertyType = $entityDto->getPropertyDataType($filterDto->getProperty());
28+
if (!isset($entityDto->getClassMetadata()->fieldMappings[$filterDto->getProperty()])) {
29+
return;
30+
}
31+
32+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
33+
/** @var FieldMapping|array $fieldMapping */
34+
/** @phpstan-ignore-next-line */
35+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($filterDto->getProperty());
36+
if (\is_array($fieldMapping)) {
37+
$doctrineFieldMappingType = $fieldMapping['type'];
38+
} else {
39+
$doctrineFieldMappingType = $fieldMapping->type;
40+
}
2841

29-
if (Types::DECIMAL === $propertyType) {
42+
if (Types::DECIMAL === $doctrineFieldMappingType) {
3043
$filterDto->setFormTypeOptionIfNotSet('value_type_options.input', 'string');
3144
}
3245

33-
if (\in_array($propertyType, [Types::BIGINT, Types::INTEGER, Types::SMALLINT], true)) {
46+
if (\in_array($doctrineFieldMappingType, [Types::BIGINT, Types::INTEGER, Types::SMALLINT], true)) {
3447
$filterDto->setFormTypeOptionIfNotSet('value_type', IntegerType::class);
3548
}
3649
}

src/Filter/Configurator/TextConfigurator.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\Filter\Configurator;
44

55
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\FieldMapping;
67
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
78
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterConfiguratorInterface;
89
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
@@ -24,14 +25,26 @@ public function supports(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $e
2425

2526
public function configure(FilterDto $filterDto, ?FieldDto $fieldDto, EntityDto $entityDto, AdminContext $context): void
2627
{
27-
$propertyType = $entityDto->getPropertyDataType($filterDto->getProperty());
28+
if (!isset($entityDto->getClassMetadata()->fieldMappings[$filterDto->getProperty()])) {
29+
return;
30+
}
31+
32+
// Doctrine ORM 2.x returns an array and Doctrine ORM 3.x returns a FieldMapping object
33+
/** @var FieldMapping|array $fieldMapping */
34+
/** @phpstan-ignore-next-line */
35+
$fieldMapping = $entityDto->getClassMetadata()->getFieldMapping($filterDto->getProperty());
36+
if (\is_array($fieldMapping)) {
37+
$doctrineFieldMappingType = $fieldMapping['type'];
38+
} else {
39+
$doctrineFieldMappingType = $fieldMapping->type;
40+
}
2841

29-
if (Types::JSON === $propertyType) {
42+
if (Types::JSON === $doctrineFieldMappingType) {
3043
$filterDto->setFormTypeOption('value_type', TextareaType::class);
3144
}
3245

3346
// don't use Types::OBJECT because it was removed in Doctrine ORM 3.0
34-
if (\in_array($propertyType, [Types::BLOB, 'object', Types::TEXT], true)) {
47+
if (\in_array($doctrineFieldMappingType, [Types::BLOB, 'object', Types::TEXT], true)) {
3548
$filterDto->setFormTypeOptionIfNotSet('value_type', TextareaType::class);
3649
}
3750
}

0 commit comments

Comments
 (0)