Skip to content
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

Object that are not entities are checked for Metadata without cache #96

Open
bastnic opened this issue Feb 13, 2020 · 1 comment
Open

Comments

@bastnic
Copy link

bastnic commented Feb 13, 2020

This is a followup of doctrine/dbal#3838, I just want to check if maintainers see a room for improvement.

TL;DR: when we check metadata for doctrine entities, there is a cache that prevents checking for metadata across requests and there is memoization to prevent hitting on the cache. When passing objects that are not doctrine entities with fallback there is no cache but memoization, and without fallback there is none of that.

There are at least two paths that trigger that behavior (just to show that this is not an easy fix in userland):

1/ doctrine query with datetime parameter without the third parameter "datetime" (dev and prod)

$q = $em->createQuery('SELECT d from App\Entity\DataSample d WHERE d.referenceDate = :date');
$q->setParameter('date', Carbon::now(), 'datetime');

This is fixable in userland, but quite not fun.

This is a blackfire profile in prod env with 20 sql requests with a datetime parameter WITHOUT the third parameter set. The after is a simple test at the beginning of the getMetadataFor to avoid loading the metadata stack:

        if ($className === 'DateTime') {
            throw new MappingException();
        }

image

2/ symfony validation (dev only)

3/ doctrine embedable classes


I don't know the best fix for that but I figures that on the life on a request / cache, this should not happen. Even I who know this bug, I forgot to add the third parameter, it should really be resolved in doctrine/persistence.

We could:

  • cache the exception and add some instanceof / throw somewhere.
  • cache null and return an exception if null, we should change the isset by array_key_exists
@greg0ire
Copy link
Member

IMO the most BC way would be to add a new array, and cache exceptions in that array, that way you are sure to throw the same type of exception as before. The issue is that it will be an exception with an outdated stack trace. It's an issue but ideally (in the future), that code path should not even be used by apps. There should be a new method (that would have been named hasMetadataFor, but will not because that name is already taken for something that seems completely useless) that returns a boolean and that you would be supposed to check before calling loadMetadataFor, because relying on exceptions for things that are not exceptional does not make a lot of sense. Since loadedMetadata is exposed through getLoadedMetadata, touching that array is a no-go, even though it is private and even though that method does not seem to relied on much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants