1

Prior to beginning upgrade work to update my application to Symfony 3, and with it upgrading several libraries (including Doctrine) to more recent versions, I was able to compare references in a query to the results of an earlier query. I was able to do this by matching the derived class name (e.g. get_class($source)) of each item in the results of the earlier query to the _doctrine_class_name field on a database reference in the new query. This would properly filter out documents that were of the incorrect type.

Since upgrading my dependencies, when I get the derived class name of the source, I am getting back a proxy instead of the actual class name, e.g. MongoDBODMProxies\\__CG__\\AcmeBundle\\Documents\\MyClass instead of AcmeBundle\Documents\MyClass.

The collection of objects I am trying to filter in this case are Activity objects, among their properties is a $source property which is an open type, that is to say that there is no explicit discriminator map for it as I wanted it to potentially be able to hold any document. What I am trying to get working again is a query that filters these activities by their matching sources, using ID and class name. The query code looks like this:

public function findAllBySource($sources = array(), $date = null, $limit = 50)
{
    $qb = $this->createQueryBuilder()->limit($limit)->sort('date', 'DESC');

    if (!empty($date)) {
        $qb->field('date')->lte($date);
    }

    $qb->addOr($qb->expr()->field('source')->exists(false));
    foreach ($sources as $source) {
        // $source is initialized as a proxy to the real class here
        // using get_class($source) returns the class name to the
        // proxy, not the actual FQCN, e.g. AcmeBundle\Document\MyClass
        $expr = $qb->expr()
            ->field('source.$id')->equals(new \MongoId($source->getId()))
            ->field('source._doctrine_class_name')->equals(get_class($source));
        $qb->addOr($expr);
    }
    $query = $qb->getQuery();
    return array_values($query->execute()->toArray());
}

For what it is worth, I am using the following versions of the Doctrine and MongoDB ODM/bundles:

  • doctrine/mongodb ^1.3.0
  • doctrine/mongodb-odm ^1.1.0
  • doctrine/mongodb-odm-bundle ^3.2.0
Sean Quinn
  • 2,131
  • 1
  • 18
  • 48
  • Just to clarify, are you looking to get "MyClass" instead of "MongoDBODMProxies\\__CG__\\...\\MyClass"? – anFfWuy7qbJWaPp6DSOR Jul 20 '16 at 03:41
  • Sorry, I should be have been more clear, yes and no: I want the FQCN sans the proxy prefix, so basically the actual FQCN of the class, so if the class was located in `AcmeBundle\Documents\MyClass` and the proxy class showed `MongoDBODMProxies\\__CG__\\AcmeBundle\\Documents\\MyClass` I would want the `AcmeBundle\Documents\MyClass` class name. I'll update to add that clarity. – Sean Quinn Jul 20 '16 at 03:59

1 Answers1

2

Check out the getClass from ClassUtils class (part of Doctrine Common):

<?php

// $source is an instance of MongoDBODMProxies\\__CG__\\AcmeBundle\\Documents\\MyClass

$source = Doctrine\Common\Util\ClassUtils::getClass($source);

echo $source; // $source should now be "AcmeBundle\Documents\MyClass"
  • That is awesome. It's odd though, `getRealClass` seemed to supply additional data at the end of the class name that looked like a positional marker (`@XXXXX`) and didn't work, but when I used `getClass` from the class utils everything worked. It might have just been an odd side effect. Still thank you very much for pointing me to that utility, I wasn't aware of it previously! – Sean Quinn Jul 20 '16 at 12:42
  • After reading the code of ClassUtils a bit more closely, it appears using getClass is correct. $source is an instance, not a string - my mistake. Glad I could be of help. Thanks! – anFfWuy7qbJWaPp6DSOR Jul 20 '16 at 12:44