Skip to content

Commit 63c52a1

Browse files
weaverryanGeekimojrushlow
authored
[make:entity] Property types, Types:: constant & type guessing (#1147)
* feat(entity): Add use of Doctrine types constants in attributes * fix: Fix tests * fix: Fix tests * only handle attribute nodes * php-cs-fixer it up * fix entity regen tests * upgrading phpcs fixer and fixing * Adding support for make:entity property types Also dropping the Column(type:) argument when it can be inferred from the property type. * changing more test fixtures to new coding style * Fixes and test fixes * more test fixing * phpcs * minor thanks to Jesse Co-authored-by: Morgan Abraham <[email protected]> Co-authored-by: Jesse Rushlow <[email protected]>
1 parent 1605898 commit 63c52a1

File tree

113 files changed

+696
-559
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+696
-559
lines changed

src/DependencyInjection/CompilerPass/MakeCommandRegistrationPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function process(ContainerBuilder $container): void
4545
$tagAttributes = ['command' => $class::getCommandName()];
4646

4747
if (!method_exists($class, 'getCommandDescription')) {
48-
// no-op
48+
// no-op
4949
} elseif (class_exists(LazyCommand::class)) {
5050
$tagAttributes['description'] = $class::getCommandDescription();
5151
} else {

src/Doctrine/DoctrineHelper.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\MakerBundle\Doctrine;
1313

1414
use Doctrine\DBAL\Connection;
15+
use Doctrine\DBAL\Types\Types;
1516
use Doctrine\ORM\EntityManagerInterface;
1617
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
1718
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
@@ -24,6 +25,8 @@
2425
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
2526
use Doctrine\Persistence\Mapping\MappingException as PersistenceMappingException;
2627
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
28+
use Symfony\Component\Uid\Ulid;
29+
use Symfony\Component\Uid\Uuid;
2730

2831
/**
2932
* @author Fabien Potencier <[email protected]>
@@ -230,6 +233,64 @@ public function isClassAMappedEntity(string $className): bool
230233
return (bool) $this->getMetadata($className);
231234
}
232235

236+
/**
237+
* Determines if the property-type will make the column type redundant.
238+
*
239+
* See ClassMetadataInfo::validateAndCompleteTypedFieldMapping()
240+
*/
241+
public static function canColumnTypeBeInferredByPropertyType(string $columnType, string $propertyType): bool
242+
{
243+
// todo: guessing on enum's could be added
244+
245+
return match ($propertyType) {
246+
'\\'.\DateInterval::class => Types::DATEINTERVAL === $columnType,
247+
'\\'.\DateTime::class => Types::DATETIME_MUTABLE === $columnType,
248+
'\\'.\DateTimeImmutable::class => Types::DATETIME_IMMUTABLE === $columnType,
249+
'array' => Types::JSON === $columnType,
250+
'bool' => Types::BOOLEAN === $columnType,
251+
'float' => Types::FLOAT === $columnType,
252+
'int' => Types::INTEGER === $columnType,
253+
'string' => Types::STRING === $columnType,
254+
default => false,
255+
};
256+
}
257+
258+
public static function getPropertyTypeForColumn(string $columnType): ?string
259+
{
260+
return match ($columnType) {
261+
Types::STRING, Types::TEXT, Types::GUID, Types::BIGINT, Types::DECIMAL => 'string',
262+
Types::ARRAY, Types::SIMPLE_ARRAY, Types::JSON => 'array',
263+
Types::BOOLEAN => 'bool',
264+
Types::INTEGER, Types::SMALLINT => 'int',
265+
Types::FLOAT => 'float',
266+
Types::DATETIME_MUTABLE, Types::DATETIMETZ_MUTABLE, Types::DATE_MUTABLE, Types::TIME_MUTABLE => '\\'.\DateTimeInterface::class,
267+
Types::DATETIME_IMMUTABLE, Types::DATETIMETZ_IMMUTABLE, Types::DATE_IMMUTABLE, Types::TIME_IMMUTABLE => '\\'.\DateTimeImmutable::class,
268+
Types::DATEINTERVAL => '\\'.\DateInterval::class,
269+
Types::OBJECT => 'object',
270+
'uuid' => '\\'.Uuid::class,
271+
'ulid' => '\\'.Ulid::class,
272+
default => null,
273+
};
274+
}
275+
276+
/**
277+
* Given the string "column type", this returns the "Types::STRING" constant.
278+
*
279+
* This is, effectively, a reverse lookup: given the final string, give us
280+
* the constant to be used in the generated code.
281+
*/
282+
public static function getTypeConstant(string $columnType): ?string
283+
{
284+
$reflection = new \ReflectionClass(Types::class);
285+
$constants = array_flip($reflection->getConstants());
286+
287+
if (!isset($constants[$columnType])) {
288+
return null;
289+
}
290+
291+
return sprintf('Types::%s', $constants[$columnType]);
292+
}
293+
233294
private function isInstanceOf($object, string $class): bool
234295
{
235296
if (!\is_object($object)) {

src/Doctrine/EntityClassGenerator.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use ApiPlatform\Metadata\ApiResource;
1515
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
16-
use Doctrine\ORM\Mapping;
1716
use Doctrine\Persistence\ManagerRegistry;
1817
use Symfony\Bundle\MakerBundle\Generator;
1918
use Symfony\Bundle\MakerBundle\Str;
@@ -48,7 +47,7 @@ public function generateEntityClass(ClassNameDetails $entityClassDetails, bool $
4847

4948
$useStatements = new UseStatementGenerator([
5049
$repoClassDetails->getFullName(),
51-
[Mapping::class => 'ORM'],
50+
['Doctrine\\ORM\\Mapping' => 'ORM'],
5251
]);
5352

5453
if ($broadcast) {

src/Maker/MakeFunctionalTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
6565
$pantherAvailable = trait_exists(PantherTestCaseTrait::class);
6666

6767
$useStatements = new UseStatementGenerator([
68-
($pantherAvailable ? PantherTestCase::class : WebTestCase::class),
68+
$pantherAvailable ? PantherTestCase::class : WebTestCase::class,
6969
]);
7070

7171
$generator->generateClass(

src/Maker/MakeResetPassword.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,15 +423,15 @@ private function generateRequestEntity(Generator $generator, ClassNameDetails $r
423423
CODE
424424
);
425425

426-
$manipulator->addManyToOneRelation((new RelationManyToOne(
426+
$manipulator->addManyToOneRelation(new RelationManyToOne(
427427
propertyName: 'user',
428428
targetClassName: $this->userClass,
429429
mapInverseRelation: false,
430430
avoidSetter: true,
431431
isCustomReturnTypeNullable: false,
432432
customReturnType: 'object',
433433
isOwning: true,
434-
)));
434+
));
435435

436436
$this->fileManager->dumpFile($requestEntityPath, $manipulator->getSourceCode());
437437

src/Resources/skeleton/doctrine/Entity.tpl.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ class <?= $class_name."\n" ?>
1717
{
1818
#[ORM\Id]
1919
#[ORM\GeneratedValue]
20-
#[ORM\Column(type: 'integer')]
21-
private int $id;
20+
#[ORM\Column()]
21+
private ?int $id = null;
2222

2323
public function getId(): ?int
2424
{

src/Resources/skeleton/registration/RegistrationController.tpl.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function register(Request $request, <?= $password_hasher_class_details->g
2525
if ($form->isSubmitted() && $form->isValid()) {
2626
// encode the plain password
2727
$user->set<?= ucfirst($password_field) ?>(
28-
<?= $password_hasher_variable_name ?>-><?= $use_password_hasher ? 'hashPassword' : 'encodePassword' ?>(
28+
<?= $password_hasher_variable_name ?>-><?= $use_password_hasher ? 'hashPassword' : 'encodePassword' ?>(
2929
$user,
3030
$form->get('plainPassword')->getData()
3131
)

0 commit comments

Comments
 (0)