feature #31486 [Doctrine][PropertyInfo] Detect if the ID is writeable (dunglas)
This PR was merged into the 4.3 branch.
Discussion
----------
[Doctrine][PropertyInfo] Detect if the ID is writeable
| Q | A
| ------------- | ---
| Branch? | 4.3
| Bug fix? | yes
| New feature? | yes <!-- please update src/**/CHANGELOG.md files -->
| BC breaks? | no <!-- see https://symfony.com/bc -->
| Deprecations? | yes/no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass? | yes <!-- please add some, will be required by reviewers -->
| Fixed tickets | n/a
| License | MIT
| Doc PR | n/a
Companion of #31481. Allows to detect that ids with a generated value aren't writable (because the DBMS will generate the ID by itself). It could be considered as a bug fix or as a new feature. I prefer to not merge in in 3.4. However, it becomes necessary for autovalidation to work with such entities, so it should be in 4.3:
```php
/**
* @Entity
*/
class Foo
{
/**
* @Id
* @GeneratedValue(strategy="AUTO")
* @Column(type="integer")
*/
public $id;
}
```
Commits
-------
4598235192
[Doctrine][PropertyInfo] Detect if the ID is writeable
This commit is contained in:
commit
0d196c46a5
@ -15,8 +15,10 @@ use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
|
|||||||
use Doctrine\Common\Persistence\Mapping\MappingException;
|
use Doctrine\Common\Persistence\Mapping\MappingException;
|
||||||
use Doctrine\DBAL\Types\Type as DBALType;
|
use Doctrine\DBAL\Types\Type as DBALType;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||||
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
|
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
|
||||||
|
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
|
||||||
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
|
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
|
||||||
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
||||||
use Symfony\Component\PropertyInfo\Type;
|
use Symfony\Component\PropertyInfo\Type;
|
||||||
@ -26,7 +28,7 @@ use Symfony\Component\PropertyInfo\Type;
|
|||||||
*
|
*
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
*/
|
*/
|
||||||
class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface
|
class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface
|
||||||
{
|
{
|
||||||
private $entityManager;
|
private $entityManager;
|
||||||
private $classMetadataFactory;
|
private $classMetadataFactory;
|
||||||
@ -51,12 +53,8 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE
|
|||||||
*/
|
*/
|
||||||
public function getProperties($class, array $context = [])
|
public function getProperties($class, array $context = [])
|
||||||
{
|
{
|
||||||
try {
|
if (null === $metadata = $this->getMetadata($class)) {
|
||||||
$metadata = $this->entityManager ? $this->entityManager->getClassMetadata($class) : $this->classMetadataFactory->getMetadataFor($class);
|
return null;
|
||||||
} catch (MappingException $exception) {
|
|
||||||
return;
|
|
||||||
} catch (OrmMappingException $exception) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());
|
$properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());
|
||||||
@ -77,12 +75,8 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE
|
|||||||
*/
|
*/
|
||||||
public function getTypes($class, $property, array $context = [])
|
public function getTypes($class, $property, array $context = [])
|
||||||
{
|
{
|
||||||
try {
|
if (null === $metadata = $this->getMetadata($class)) {
|
||||||
$metadata = $this->entityManager ? $this->entityManager->getClassMetadata($class) : $this->classMetadataFactory->getMetadataFor($class);
|
return null;
|
||||||
} catch (MappingException $exception) {
|
|
||||||
return;
|
|
||||||
} catch (OrmMappingException $exception) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($metadata->hasAssociation($property)) {
|
if ($metadata->hasAssociation($property)) {
|
||||||
@ -176,6 +170,39 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isReadable($class, $property, array $context = [])
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isWritable($class, $property, array $context = [])
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
null === ($metadata = $this->getMetadata($class))
|
||||||
|
|| ClassMetadata::GENERATOR_TYPE_NONE === $metadata->generatorType
|
||||||
|
|| !\in_array($property, $metadata->getIdentifierFieldNames(), true)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMetadata(string $class): ?ClassMetadata
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->entityManager ? $this->entityManager->getClassMetadata($class) : $this->classMetadataFactory->getMetadataFor($class);
|
||||||
|
} catch (MappingException | OrmMappingException $exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether an association is nullable.
|
* Determines whether an association is nullable.
|
||||||
*
|
*
|
||||||
|
@ -16,6 +16,7 @@ use Doctrine\ORM\EntityManager;
|
|||||||
use Doctrine\ORM\Tools\Setup;
|
use Doctrine\ORM\Tools\Setup;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
|
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
|
||||||
|
use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineGeneratedValue;
|
||||||
use Symfony\Component\PropertyInfo\Type;
|
use Symfony\Component\PropertyInfo\Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,4 +224,13 @@ class DoctrineExtractorTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->assertNull($this->createExtractor($legacy)->getTypes('Not\Exist', 'baz'));
|
$this->assertNull($this->createExtractor($legacy)->getTypes('Not\Exist', 'baz'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGeneratedValueNotWritable()
|
||||||
|
{
|
||||||
|
$extractor = $this->createExtractor();
|
||||||
|
$this->assertFalse($extractor->isWritable(DoctrineGeneratedValue::class, 'id'));
|
||||||
|
$this->assertNull($extractor->isReadable(DoctrineGeneratedValue::class, 'id'));
|
||||||
|
$this->assertNull($extractor->isWritable(DoctrineGeneratedValue::class, 'foo'));
|
||||||
|
$this->assertNull($extractor->isReadable(DoctrineGeneratedValue::class, 'foo'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping\Column;
|
||||||
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||||
|
use Doctrine\ORM\Mapping\Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||||
|
*
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DoctrineGeneratedValue
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id
|
||||||
|
* @GeneratedValue(strategy="AUTO")
|
||||||
|
* @Column(type="integer")
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column
|
||||||
|
*/
|
||||||
|
public $foo;
|
||||||
|
}
|
Reference in New Issue
Block a user