Skip to content

Commit

Permalink
Adding an error if you try to generate a class that does not use
Browse files Browse the repository at this point in the history
annotation metadata
  • Loading branch information
weaverryan committed Feb 27, 2018
1 parent 656c199 commit e535f0d
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 9 deletions.
27 changes: 27 additions & 0 deletions src/Doctrine/DoctrineMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
namespace Symfony\Bundle\MakerBundle\Doctrine;

use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;

Expand Down Expand Up @@ -69,6 +72,30 @@ public function getMetadataForClass(string $entity): ?ClassMetadata
return null;
}

public function getMappingDriverForClass(string $className): ?MappingDriver
{
/** @var EntityManagerInterface $em */
$em = $this->registry->getManagerForClass($className);

if (null === $em) {
throw new \InvalidArgumentException(sprintf('Cannot find the entity manager for class "%s"', $className));
}

$metadataDriver = $em->getConfiguration()->getMetadataDriverImpl();

if (!$metadataDriver instanceof MappingDriverChain) {
return $metadataDriver;
}

foreach ($metadataDriver->getDrivers() as $namespace => $driver) {
if (0 === strpos($className, $namespace)) {
return $driver;
}
}

return $metadataDriver->getDefaultDriver();
}

/**
* @return array
*/
Expand Down
42 changes: 35 additions & 7 deletions src/Maker/MakeEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineMetadataFactory;
use Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Str;
Expand Down Expand Up @@ -122,7 +125,8 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
'Repository'
);

if (!class_exists($entityClassDetails->getFullName())) {
$classExists = class_exists($entityClassDetails->getFullName());
if (!$classExists) {
$entityPath = $generator->generateClass(
$entityClassDetails->getFullName(),
'doctrine/Entity.tpl.php',
Expand All @@ -143,21 +147,26 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
);

$generator->writeChanges();
}

if (!$this->doesEntityUseAnnotationMapping($entityClassDetails->getFullName())) {
throw new RuntimeCommandException(sprintf('Only annotation mapping is supported by make:entity, but the <info>%s</info> class uses a different format. If you would like this command to generate the properties & getter/setter methods, add your mapping configuration, and then re-run this command with the <info>--regenerate</info> flag.', $entityClassDetails->getFullName()));
}

if ($classExists) {
$entityPath = $this->getPathOfClass($entityClassDetails->getFullName());
$io->text([
'',
'Entity generated! Now let\'s add some fields!',
'You can always add more fields later manually or by re-running this command.',
'Your entity already exists! So let\'s add some new fields!',
]);
} else {
$entityPath = $this->getPathOfClass($entityClassDetails->getFullName());
$io->text([
'Your entity already exists! So let\'s add some new fields!',
'',
'Entity generated! Now let\'s add some fields!',
'You can always add more fields later manually or by re-running this command.',
]);
}

$currentFields = $this->getPropertyNames($entityClassDetails->getFullName());

$manipulator = $this->createClassManipulator($entityPath, $io, $overwrite);

$isFirstField = true;
Expand Down Expand Up @@ -782,4 +791,23 @@ private function getPropertyNames(string $class): array
return $prop->getName();
}, $reflClass->getProperties());
}

private function doesEntityUseAnnotationMapping(string $className): bool
{
$metadataFactory = new DoctrineMetadataFactory($this->registry);
if (!class_exists($className)) {
$otherClassMetadatas = $metadataFactory->getMetadataForNamespace(Str::getNamespace($className));

// if we have no metadata, we should assume this is the first class being mapped
if (empty($otherClassMetadatas)) {
return false;
}

$className = $otherClassMetadatas[0]->name;
}

$metadataFactory->getMappingDriverForClass($className);

return $metadataFactory instanceof AnnotationDriver;
}
}
2 changes: 1 addition & 1 deletion src/Test/MakerTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ protected function executeMakerCommand(MakerTestDetails $testDetails)

$makerProcess->run();

if (!$makerProcess->isSuccessful()) {
if (!$makerProcess->isSuccessful() && !$testDetails->isCommandAllowedToFail()) {
throw new \Exception(sprintf('Running maker command failed: "%s" "%s"', $makerProcess->getOutput(), $makerProcess->getErrorOutput()));
}

Expand Down
14 changes: 14 additions & 0 deletions src/Test/MakerTestDetails.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ final class MakerTestDetails

private $argumentsString = '';

private $commandAllowedToFail = false;

/**
* @param MakerInterface $maker
* @param array $inputs
Expand Down Expand Up @@ -153,6 +155,13 @@ public function setArgumentsString(string $argumentsString): self
return $this;
}

public function setCommandAllowedToFail(bool $commandAllowedToFail): self
{
$this->commandAllowedToFail = $commandAllowedToFail;

return $this;
}

public function getInputs(): array
{
return $this->inputs;
Expand Down Expand Up @@ -216,4 +225,9 @@ public function getArgumentsString(): string
{
return $this->argumentsString;
}

public function isCommandAllowedToFail(): bool
{
return $this->commandAllowedToFail;
}
}
48 changes: 47 additions & 1 deletion tests/Maker/FunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public function getCommandTests()
->updateSchemaAfterCommand()
];

yield 'entity_many_to_one_simple' => [MakerTestDetails::createTest(
yield 'entity_many_to_one_simple_with_inverse' => [MakerTestDetails::createTest(
$this->getMakerInstance(MakeEntity::class),
[
// entity class name
Expand Down Expand Up @@ -476,6 +476,52 @@ public function getCommandTests()
->configureDatabase(false)
];

yield 'entity_xml_mapping_error_existing' => [MakerTestDetails::createTest(
$this->getMakerInstance(MakeEntity::class),
[
'User',
])
->setFixtureFilesPath(__DIR__ . '/../fixtures/MakeEntityXmlMappingError')
->addReplacement(
'config/packages/doctrine.yaml',
'type: annotation',
'type: xml'
)
->addReplacement(
'config/packages/doctrine.yaml',
"dir: '%kernel.project_dir%/src/Entity'",
"dir: '%kernel.project_dir%/config/doctrine'"
)
->configureDatabase(false)
->setCommandAllowedToFail(true)
->assert(function(string $output, string $directory) {
$this->assertContains('Only annotation mapping is supported', $output);
})
];

yield 'entity_xml_mapping_error_new_class' => [MakerTestDetails::createTest(
$this->getMakerInstance(MakeEntity::class),
[
'UserAvatarPhoto',
])
->setFixtureFilesPath(__DIR__ . '/../fixtures/MakeEntityXmlMappingError')
->addReplacement(
'config/packages/doctrine.yaml',
'type: annotation',
'type: xml'
)
->addReplacement(
'config/packages/doctrine.yaml',
"dir: '%kernel.project_dir%/src/Entity'",
"dir: '%kernel.project_dir%/config/doctrine'"
)
->configureDatabase(false)
->setCommandAllowedToFail(true)
->assert(function(string $output, string $directory) {
$this->assertContains('Only annotation mapping is supported', $output);
})
];

yield 'entity_updating_overwrite' => [MakerTestDetails::createTest(
$this->getMakerInstance(MakeEntity::class),
[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<entity name="App\Entity\User">
<id name="id" type="integer">
<generator strategy="AUTO" />
</id>
<one-to-many field="avatars" target-entity="UserAvatar" mapped-by="user" />
</entity>
</doctrine-mapping>
16 changes: 16 additions & 0 deletions tests/fixtures/MakeEntityXmlMappingError/src/Entity/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Entity;

class User
{
private $id;

public function getId(): ?int
{
// custom comment
return $this->id;
}

// add your own fields
}

0 comments on commit e535f0d

Please sign in to comment.