Skip to content

[DoctrineBridge][PropertyInfo] Added support for Doctrine Embeddables #23023

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from

Conversation

vudaltsov
Copy link
Contributor

Q A
Branch? 2.8 and higher
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets
License MIT
Doc PR

Note that Embeddables appeared only in doctrine/orm 2.5. I added class_exists checks for that.

"doctrine/orm": "^2.5" only
return;
}

$expectedTypes = [new Type(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use array() instead of []

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you, changed PHP version to 5.3 in PhpStorm for this project and fixed declaration

@nicolas-grekas nicolas-grekas added this to the 2.8 milestone Jun 1, 2017
@vudaltsov
Copy link
Contributor Author

vudaltsov commented Jun 1, 2017

Suddenly I faced another problem with embeddables.

When an entity has properties with embeddables, Doctrine\Common\Persistence\Mapping\ClassMetadata::getFieldNames() returns property paths for them. Example:

/**
 * @ORM\Entity
 */
class DoctrineWithEmbedded
{
    /**
     * @Id
     * @Column(type="smallint")
     */
    public $id;

    /**
     * @Embedded(class="DoctrineEmbeddable")
     */
    protected $embedded;
}

/**
 * @ORM\Embeddable
 */
class DoctrineEmbeddable
{
    /**
     * @Column(type="string")
     */
    protected $field;
}

$container->get('doctrine.orm.default_entity_manager.metadata_factory')
    ->getMetadataFor('DoctrineWithEmbedded')
    ->getFieldNames();

// returns
[
    'id',
    'embedded.field',
];

Fixed DoctrineExtractor::getProperties() in the next commit.

public function testGetEmbeddableProperties()
{
if (!class_exists('Doctrine\ORM\Mapping\Embedded')) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should put $this->markTestSkipped() with message that embedded is not available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, fixed this!

public function testExtractEmbeddable()
{
if (!class_exists('Doctrine\ORM\Mapping\Embedded')) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@vudaltsov
Copy link
Contributor Author

@nicolas-grekas, anything else needed here? could it be merged?

@dunglas
Copy link
Member

dunglas commented Jun 14, 2017

This should be merged in 3.4 (it's a new feature, not a bug fix).

Copy link
Member

@dunglas dunglas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement! I just left some minor comments.

$properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());

if (class_exists('Doctrine\ORM\Mapping\Embedded')) {
if ($metadata instanceof ClassMetadataInfo && count($metadata->embeddedClasses) > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& $metadata->embeddedClasses will be faster.

return array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());
$properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());

if (class_exists('Doctrine\ORM\Mapping\Embedded')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we'll merge this PR in 3.4, you can import this class and do class_exists(Embedded::class).

@@ -105,6 +117,16 @@ public function getTypes($class, $property, array $context = array())
));
}

if (class_exists('Doctrine\ORM\Mapping\Embedded')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, same in tests.

@vudaltsov
Copy link
Contributor Author

vudaltsov commented Jun 14, 2017

@dunglas, the problem is that now when you do

$container
    ->get('doctrine.orm.default_entity_manager.property_info_extractor')
    ->getProperties(DoctrineWithEmbedded::class); // the class from my example above

you receive

[
    'id',
    'embedded.field', // but not `embedded`
];

which is not what developer might expect.

So it appears that currently 2.8 doesn't fully support ORM, which might lead to unexpected behaviour. Isn't it a bug?

@dunglas
Copy link
Member

dunglas commented Jun 29, 2017

Ok to consider it a bug fix then. 👍

ping @symfony/deciders

@vudaltsov
Copy link
Contributor Author

vudaltsov commented Jul 13, 2017

anything else needed here?

$properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());

if (class_exists('Doctrine\ORM\Mapping\Embedded')) {
if ($metadata instanceof ClassMetadataInfo && $metadata->embeddedClasses) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be merge with the previous if condition

@@ -105,6 +117,16 @@ public function getTypes($class, $property, array $context = array())
));
}

if (class_exists('Doctrine\ORM\Mapping\Embedded')) {
if ($metadata instanceof ClassMetadataInfo && isset($metadata->embeddedClasses[$property])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, you can merge the 2 conditions.

Type::BUILTIN_TYPE_OBJECT,
false,
$metadata->embeddedClasses[$property]['class']
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be on one line

return array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());
$properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());

if (class_exists('Doctrine\ORM\Mapping\Embedded') && $metadata instanceof ClassMetadataInfo && $metadata->embeddedClasses) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you call class_exists after the other tests (for perf, function calls cost more than other checks)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dunglas, when class Doctrine\ORM\Mapping\Embedded doesn't exist, $metadata->embeddedClasses is not defined. I can only move instanceof check to the first place.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok can you do that? Then I'll merge :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dunglas, done!

@dunglas
Copy link
Member

dunglas commented Jul 22, 2017

Thank you @vudaltsov.

dunglas added a commit that referenced this pull request Jul 22, 2017
…Embeddables (vudaltsov)

This PR was squashed before being merged into the 2.8 branch (closes #23023).

Discussion
----------

[DoctrineBridge][PropertyInfo] Added support for Doctrine Embeddables

| Q             | A
| ------------- | ---
| Branch?       | 2.8 and higher
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

Note that [Embeddables appeared only in doctrine/orm 2.5](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/changelog/migration_2_5.html). I added class_exists checks for that.

Commits
-------

7816f3b [DoctrineBridge][PropertyInfo] Added support for Doctrine Embeddables
@dunglas dunglas closed this Jul 22, 2017
@vudaltsov vudaltsov deleted the 2.8 branch July 31, 2017 19:51
This was referenced Aug 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants