Skip to content

Much faster method for getting Metadata of a class #152

Closed
wants to merge 3 commits into from

4 participants

@michaelperrin

Since commit cc6673 resolving issue #2688, generating entities with the app/console doctrine:generate:entities command have become very slow, especially with many entities.

The problem comes from the getMetadataForClass method of the Doctrine\Bundle\DoctrineBundle\Mapping\MetadataFactory class which was looking for the right class after getting the metadata of all classes.
I changed the implementation so that only the metadata of the given class is retrieved.
Generating my entities is now about 12 times faster in my project.

Maybe we should consider updating all these classes to the latest version of the jms metadata project (https://github.com/schmittjoh/metadata) in the future.

edit: removed last sentence

@michaelperrin michaelperrin Much faster method for getting Metadata of a class
Instead of looking for the right class after getting the metadata of all classes, just get the metadata of the given class.
8c02f0d
@stof
Doctrine member
stof commented Jan 16, 2013

These classes have nothing to do with the JMS Matadata library

@michaelperrin

Indeed, sorry!

@stloyd stloyd commented on an outdated diff Jan 16, 2013
Mapping/MetadataFactory.php
@@ -173,10 +173,13 @@ private function getMetadataForNamespace($namespace)
*/
private function getMetadataForClass($entity)
{
- foreach ($this->getAllMetadata() as $metadata) {
- if ($metadata->name === $entity) {
- return new ClassMetadataCollection(array($metadata));
- }
+ foreach ($this->registry->getManagers() as $em) {
+ $class = $this->getClassMetadataFactoryClass();
+ $cmf = new $class();
@stloyd
stloyd added a note Jan 16, 2013

Both lines could be moved outside loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stloyd stloyd commented on an outdated diff Jan 16, 2013
Mapping/MetadataFactory.php
@@ -173,10 +173,13 @@ private function getMetadataForNamespace($namespace)
*/
private function getMetadataForClass($entity)
{
- foreach ($this->getAllMetadata() as $metadata) {
- if ($metadata->name === $entity) {
- return new ClassMetadataCollection(array($metadata));
- }
+ foreach ($this->registry->getManagers() as $em) {
+ $class = $this->getClassMetadataFactoryClass();
+ $cmf = new $class();
+ $cmf->setEntityManager($em);
+
+ $metadata = $cmf->getMetadataFor($entity);
+ return new ClassMetadataCollection(array($metadata));
@stloyd
stloyd added a note Jan 16, 2013

Missing new line before return.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@michaelperrin

Thanks @stloyd for your comments. I just made a new commit dealing with your comments.
I actually tried to mimic the code style of other methods of the same class, but that wasn't a good idea!

@michaelperrin

@stloyd Did you have time to check the latest coding style changes I made? Tell me if anything else needs to be done.

@stof stof and 1 other commented on an outdated diff Mar 5, 2013
Mapping/MetadataFactory.php
@@ -173,10 +173,16 @@ private function getMetadataForNamespace($namespace)
*/
private function getMetadataForClass($entity)
{
- foreach ($this->getAllMetadata() as $metadata) {
- if ($metadata->name === $entity) {
- return new ClassMetadataCollection(array($metadata));
- }
+ $entityManagers = $this->registry->getManagers();
+ $metadataFactoryClassName = $this->getClassMetadataFactoryClass();
+
+ foreach ($entityManagers as $em) {
+ $cmf = new $metadataFactoryClassName();
+ $cmf->setEntityManager($em);
+
+ $metadata = $cmf->getMetadataFor($entity);
+
+ return new ClassMetadataCollection(array($metadata));
@stof
Doctrine member
stof added a note Mar 5, 2013

This looks wrong to me. It always return for the first entity manager even when it is not the manager related to the entity.

@michaelperrin
michaelperrin added a note Mar 6, 2013

Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@michaelperrin michaelperrin Retrieve class metadata for all entity managers
An entity could have several entity managers associated to it
(which doesn't happen often I guess). Metadata from the right entity
manager is now retrieved anyway.
bf632d0
@michaelperrin

@stof problem regarding entity managers is now fixed.

@michaelperrin

Any news on this PR? Any comments are welcome.

@Padam87
Padam87 commented Sep 20, 2013

IMO this would be better:

    private function getMetadataForClass($entity)
    {
        $em = $this->registry->getManagerForClass($entity);

        if ($em === null) {
            return new ClassMetadataCollection(array());
        }

        $class = $this->getClassMetadataFactoryClass();
        $cmf = new $class();
        $cmf->setEntityManager($em);

        $metadata = $cmf->getMetadataFor($entity);

        return new ClassMetadataCollection(array($metadata));
    }

A microtime diff test on a small app(~15 entities, 1 manager), for a single entity:
current(in lib): float(0.25397801399231)
after: float(0.003140926361084)

@michaelperrin :+1: , this would improve speed a lot for a large app

@stof stof added a commit that referenced this pull request Oct 12, 2013
@stof stof Improved the way to load metadata for a single class
There is no need to load metadata for all classes in this case.
Replaces #152
42983f3
@stof
Doctrine member
stof commented Oct 12, 2013

I fixed it a bit differently because your code misses the check about classes being transient before calling getMetadataFor, and because it was conflicting with my recent change

@stof stof closed this Oct 12, 2013
@michaelperrin

@stof Great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.