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

Support multiple object managers? #53

Closed
dmaicher opened this issue Feb 13, 2019 · 46 comments
Closed

Support multiple object managers? #53

dmaicher opened this issue Feb 13, 2019 · 46 comments

Comments

@dmaicher
Copy link

In my project I have multiple objectmanagers.

This currently leads to errors like:

Internal error: The class 'X' was not found in the chain configured namespaces ...

because its using the wrong objectManager (the one returned in object-manager.php) for some entities.

@dmaicher
Copy link
Author

dmaicher commented Feb 13, 2019

Probably internally we should just return the whole doctrine registry from the php file and use

https://github.com/doctrine/persistence/blob/master/lib/Doctrine/Persistence/ManagerRegistry.php#L87

?

@ondrejmirtes
Copy link
Member

Hi,
those two object managers have different entity metadata loaded? Why? How do you keep track of which one should be used where in your application?

I see two possible options:

  1. Run PHPStan twice with different configurations on different folders. This assumes that there's a clear cut in these two areas in your application - they are in different folders.
  2. Create a third object manager that has all the metadata and pass it to PHPStan. This however can lead to problems since it does not reflect the real state of your application. For example if you mention two different entities in a single DQL that are from different object managers, PHPStan would not find this error.

@dmaicher
Copy link
Author

dmaicher commented Feb 13, 2019

those two object managers have different entity metadata loaded? Why?

different databases 😉

How do you keep track of which one should be used where in your application?

doctrine bundle can handle multiple managers and we can differentiate it based on the context in our app

What do you think about my comment to use the doctrine registry for this in phpstan? is there any drawback? Thats the source of truth that knows which entity is managed by which object manager 😊

@ondrejmirtes
Copy link
Member

doctrine bundle can handle multiple managers and we can differentiate it based on the context in our app

What's the "context"?

I really don't know how the ManagerRegistry works - and I don't think that all applications using Doctrine use it. It seems too Symfony-specific.

@ondrejmirtes
Copy link
Member

Also, when analysing DQL, it really doesn't go through ClassMetadata, I already need to have an ObjectManager (EntityManager) to run the query on.

@dmaicher
Copy link
Author

What's the "context"?

I meant based on bundles/namespaces in our app.

Also, when analysing DQL, it really doesn't go through ClassMetadata, I already need to have an ObjectManager (EntityManager) to run the query on.

Yeah I guess choosing the "correct" ObjectManager for analyzing DQL could be tricky indeed 😕

Maybe running different phpstan configurations on different namespaces/folders is an option. Will have a look.

@ondrejmirtes
Copy link
Member

Maybe running different phpstan configurations on different namespaces/folders is an option. Will have a look.

If you differentiate based on that, it sounds usable :)

I'm gonna keep this open since more people might have this problem, so it should be somehow supported.

@alcaeus
Copy link

alcaeus commented Feb 14, 2019

It seems too Symfony-specific.

Not at all: https://github.com/doctrine/persistence/blob/790cc20de53d0e4c943b36c8513401bfb5f34cf1/lib/Doctrine/Persistence/ManagerRegistry.php#L8.

The concept of having multiple entity managers is not limited to Symfony, nor is it an anti-pattern. People who use multiple object managers can use a registry to fetch a manager by name or to fetch the manager responsible for a given entity/class. In fact, this bundle even supports returning the correct repository type for a given object: #46.

The option of having multiple configurations is a workaround, not a solution. For example, in one of our applications we use both MongoDB ODM and ORM. This also means that classes might very well use an EntityManager and a DocumentManager. The extension should support multiple object managers. As is, the feature is incomplete.

@ondrejmirtes
Copy link
Member

ondrejmirtes commented Feb 15, 2019

My point is that in Doctrine itself, there's only the interface and an abstract class. Not all projects use the ManagerRegistry. BTW: It looks just like a service locator pattern under a different name to me ;)

There's some problems around this if I wanted to add support - I have no way of testing it. And I don't know what are the common patterns:

Is that you inject ManagerRegistry into your class-that-uses-EM (just call it service from now on) like this?

/** @var ManagerRegistry */
private $managerRegistry;

public function __construct(ManagerRegistry $managerRegistry)
{
    $this->managerRegistry = $managerRegistry;
}

And use it later like this:

$this->managerRegistry->getManager('a')->getRepository(FooEntity::class)->...

Or is it rather like this?

/** @var EntityManager */
private $entityManager;

public function __construct(ManagerRegistry $managerRegistry)
{
    $this->entityManager = $managerRegistry->getManager('a');
}

Which makes it really difficult when the EM is used later in the class - PHPStan has no idea which one is used because it just sees the property phpDoc. It would have to be annotated like EntityManager<a> which is really ugly.

I can imagine some other combinations too. My point is that it's really difficult to support all of them generally so I must hard-code every pattern like this...

@dmaicher
Copy link
Author

In our app we

  • get the manager by name from the registry
  • or directly inject one of the managers by DI configuration into some classes

So without checking the DI config there is no way to always know which manager is used inside some class for phpstan I'm afraid 😢

@luxemate
Copy link
Contributor

We, for example, have separate symfony bundle, which uses different database and has it's own doctrine config. In services.yml we have:

services:
    _defaults:
        ...
        autowire: true
        bind:
            $em: '@doctrine.orm.exchange_entity_manager'

So everywhere in this bundle where we have function(EntityManagerInterface $em) we get the correct EntityManger injected.

Also ran into that issue today while updating phpstan-doctrine to get rid of these :)

parameters:
    ignoreErrors:
        - '#Call to an undefined method Doctrine\\ORM\\EntityRepository<[a-zA-Z0-9\\_:]+>::[a-zA-Z0-9_]+\(\)#'
        - '#Method .+? should return [a-zA-Z0-9\\]+ but returns Doctrine\\ORM\\EntityRepository<[a-zA-Z0-9\\_:]+>#'
        - '#Method .+? should return [a-zA-Z0-9\\]+ but returns Doctrine\\Common\\Persistence\\ObjectRepository#'
        - '#Method .+? should return [a-zA-Z0-9\\]+ but returns Doctrine\\Common\\Persistence\\ObjectRepository#'
        - '#Property [a-zA-Z0-9\\]+::\$[a-zA-Z]+Repository \([a-zA-Z0-9\\]+\) does not accept Doctrine\\ORM\\EntityRepository<[a-zA-Z0-9\\]+>#'

@luxemate
Copy link
Contributor

luxemate commented Feb 16, 2019

Just an idea: accept an array of entity managers and retry with each of them if MappingException: The class 'X' was not found in the chain configured namespaces ... is caught.

@luxemate
Copy link
Contributor

@ondrejmirtes of course catching exceptions is a hacky workaround. This should be better:

$entityManager->getConfiguration()->getMetadataDriverImpl()->getAllClassNames();

Which returns an array of FQCN's of entites managed by that particular entity manager. Not sure about the ODM, but there must be something similar. So we'll end up with returning one entity manager, or an array of managers in object-manager.php. It's especially easy in Symfony via ManagerRegistry::getManagers().

What do you think?

@alcaeus
Copy link

alcaeus commented Feb 18, 2019

Not sure about the ODM, but there must be something similar.

The Symfony Bundle for the MongoDB ODM contains the same manager registry logic as the ORM bundle. They're separate registries but the functionality is exactly the same.

@mcfedr
Copy link
Contributor

mcfedr commented Feb 23, 2019

I personally always inject ManagerRegistry, the entity managers can be replaced, e.g. if you have an SQL error and reconnect. It probably makes sense to change the file we use for phpstan to return the manager registry which can then give us the correct entity manager pet entity. I guess for generic dql you can use the default manager and most of the time this will be correct

@luxemate
Copy link
Contributor

luxemate commented Apr 1, 2019

Just reminding that this is still a huge issue, as having more than one object manager (simply connection) makes impossible to use all the cool related functionality. :)

@ondrejmirtes
Copy link
Member

Anyone is welcome to suggest and/or contribute a solution. I haven’t come up with one yet.

@luxemate
Copy link
Contributor

luxemate commented Apr 1, 2019

@ondrejmirtes, I suggested one possible solution above in #53 (comment), but you didn't answer whether you like it or not and why. The other one is to use ManagerRegistry, which you seem to not like. I'm not sure there is option 3. :)

@ondrejmirtes
Copy link
Member

How would DQL support work with your suggestion?

@luxemate
Copy link
Contributor

luxemate commented Apr 1, 2019

@ondrejmirtes You'll need to have a list of entities and object managers that manage them, and pick a corresponding object manager before analyzing DQL. But I didn't look at how you have it implemented at the moment. That's more of a question to you: would DQL support work if you'd know which entity is managed by which object manager?

@ondrejmirtes
Copy link
Member

Currently there's no easy way to parse DQL and find which entities are used in it.

@luxemate
Copy link
Contributor

luxemate commented Apr 1, 2019

@ondrejmirtes First thing is to watch for entity name in from() calls, the second is to get entity name from knowing which repo is for which entity if there's no from() call. Since it's not possible to join across different connections, the same OM can be used for joined entities when analyzing. Or that is exactly what you mean by saying "not easy"?

Just to clarify, I just want the discussion to go on. Not trying to demand anyone to fix anything.

@ondrejmirtes
Copy link
Member

Proper DQL AST is in development for Doctrine ORM 3.0. Authors themselves expressed that the current shape is not easy to parse.

@luxemate
Copy link
Contributor

luxemate commented Apr 1, 2019

Oops, I thought about query builders for some reason (probably because we don't use DQL).

But anyway, should phpstan-doctrine parse all the DQL propperly or just couple of FROM statement variations will be enought: \Fully\Qualyfied\Class\Name and AcmeBundle:EntityName? Maybe just lock the implementation to FQCN, at least it will work then.

@mcfedr
Copy link
Contributor

mcfedr commented Apr 4, 2019

Seems like it would be valid for the moment at least to just use the default manager for DQL

@Jean85
Copy link

Jean85 commented Jul 1, 2019

No news on this issue? I have an app which uses both the ODM and the ORM, and PHPStan mistakes calls to the ODM to calls to the ORM...

@ondrejmirtes
Copy link
Member

ondrejmirtes commented Jul 1, 2019 via email

@Jean85
Copy link

Jean85 commented Jul 1, 2019

I personally use direct DI and type against EntityManager and DocumentManager, so for me the fix would be a simple "duplication" of the type mapping. But it's obviously not a general solution.

@ondrejmirtes
Copy link
Member

ondrejmirtes commented Jul 1, 2019 via email

@Jean85
Copy link

Jean85 commented Jul 1, 2019

I’m not sure how this is possible:

That's because I added the snippet of code to get the ORM from the Symfony container, so the extension has only that, and it tries to use it with ODM calls too.

I'll see if I'll have some time to create an example project.

@Jean85
Copy link

Jean85 commented Jul 1, 2019

@ondrejmirtes I've prepared a small test project: https://github.com/Jean85/phpstan-doctrine-demo

The docker setup is maybe a bit broken, I'll probably fix it tomorrow, but the PHPStan analysis works fine, in the sense that it reports the same error I get locally.

@kevin-emo
Copy link

kevin-emo commented Feb 12, 2020

Hey, we use PHPStan on level 8 with the latest Symfony 5.0 stack and have discovered a new behaviour which appeared along the PHPStan 0.12.9 release :X.

In fact, we already knew that the Doctrine objectManagerLoader was only able to use one entityManager at a time, which is why we provided it with the "default" declared one of Symfony, but we also use a second one called "async" to handle side asynchronous processes executed in our application 8).

The problem here is that using it that way does obviously trigger the following error, despite the fact that it is a totally legit use of entityManagers ;) :

 ------ -------------------------------------------------------------------------------------------------------------------------------
  Line   Path/Service/ServiceTest.php
 ------ -------------------------------------------------------------------------------------------------------------------------------
         Internal error: The class 'Path\Entity\Test' was not found in the chain configured namespaces App\Entity, ...
         Run PHPStan with --debug option and post the stack trace to:
         https://github.com/phpstan/phpstan/issues/new

We used to ignore this expected error with the following regex under the ignoreErrors node of the configuration file : - '#^Internal error: The class .* was not found in the chain configured namespaces .*#' but it doesn't work properly anymore since we get the following error message in return :V : https://github.com/phpstan/phpstan/issues/new" cannot be ignored, use excludes_analyse instead..

But using the excludes_analyse node of the configuration file doesn't seem to have any impact over this error handling :/.

What could we do next :) ?

@ondrejmirtes
Copy link
Member

@ZarcoX Open a new issue and post a stacktrace + code sample that causes this.

@kevin-emo
Copy link

@ondrejmirtes Actually, this is totally related to this issue. Your suggestion on using the --debug option in the CLI led me to the correct expected file path to put in the excludes_analyse configuration node.

What happens here is that any class attempting to call my second entityManager will error out because of the following code :

    public function __construct(ManagerRegistry $managerRegistry)
    {
        $this->entityManager = $managerRegistry->getManager('async');
    }

Which is normal since the return $kernel->getContainer()->get('doctrine')->getManager(); part in object-manager.php described in https://github.com/phpstan/phpstan-doctrine#configuration only returns the "default" entityManager of Symfony.

@localheinz
Copy link
Contributor

Any news on this one?

@OskarStark and I are running into the same issue in a project with multiple databases and multiple entity managers.

@localheinz
Copy link
Contributor

Ha, for what it's worth, @ondrejmirtes' recommendation to use a configuration per entity manager works for me.

@Jean85
Copy link

Jean85 commented May 5, 2020

@localheinz which recommendation?

@localheinz
Copy link
Contributor

@Jean85

#53 (comment)

I see two possible options:

  • Run PHPStan twice with different configurations on different folders. This assumes that there's a clear cut in these two areas in your application - they are in different folders.
  • Create a third object manager that has all the metadata and pass it to PHPStan. This however can lead to problems since it does not reflect the real state of your application. For example if you mention two different entities in a single DQL that are from different object managers, PHPStan would not find this error.

For us, option one works in a particular project.

It's not the best solution, but it works - that's what counts. I can see that there are projects where it will not work, and I'm looking forward to a solution that works with a single configuration, a single run, and multiple entity managers.

@ondrejmirtes
Copy link
Member

It's not fixed yet because I don't see how an ideal solution should work. I'm glad those workarounds work.

@Mika56
Copy link

Mika56 commented May 13, 2020

Hi, having this problem too.
Couldn't we pass a \Doctrine\Persistence\ManagerRegistry instead? ManagerRegistry defines the getManagerForClass(string $class) method that returns either the manager or null.
I've only looked quickly, but it seems to me that the changes to ObjectMetadataResolver would be minimal.

@ondrejmirtes
Copy link
Member

@Mika56 Feel free to try it and send a PR. We could detect whether objectManagerLoader file returns EntityManager or ManagerRegistry and act on that.

@adrienbrault
Copy link

Here's an object-manager.php that does not error (meaning it's probably not perfect) with multiple entity managers.

With this, \PHPStan\Rules\Doctrine\ORM\EntityColumnRule is able to report violations for both my entity managers' entities.

<?php

use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\Persistence\Mapping\ClassMetadataFactory;
use Doctrine\Persistence\ObjectManager;

require __DIR__.'/../config/bootstrap.php';

$kernel = new \App\Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$kernel->boot();

$doctrine = $kernel->getContainer()->get('doctrine');

$metadataFactory = new class($doctrine) implements ClassMetadataFactory
{
    private Registry $doctrine;

    public function __construct(Registry $doctrine)
    {
        $this->doctrine = $doctrine;
    }

    public function getAllMetadata()
    {
        $all = [];

        foreach ($this->doctrine->getManagers() as $manager) {
            $all = array_merge($all, $manager->getMetadataFactory()->getAllMetadata());
        }

        return $all;
    }

    public function getMetadataFor($className)
    {
        return $this->doctrine->getManagerForClass($className)->getClassMetadata($className);
    }

    public function isTransient($className)
    {
        $isTransient = true;

        foreach ($this->doctrine->getManagers() as $manager) {
            $isTransient = $isTransient && $manager->getMetadataFactory()->isTransient($className);
        }

        return $isTransient;
    }

    public function hasMetadataFor($className)
    {
        $hasMetadata = false;

        foreach ($this->doctrine->getManagers() as $manager) {
            $hasMetadata = $hasMetadata || $manager->getMetadataFactory()->hasMetadataFor($className);
        }

        return $hasMetadata;
    }

    public function setMetadataFor($className, $class)
    {
        throw new \Exception(__FILE__);
    }
};

return new class($doctrine, $metadataFactory) implements ObjectManager
{
    private Registry $doctrine;
    private ClassMetadataFactory $metadataFactory;

    public function __construct(Registry $doctrine, ClassMetadataFactory $metadataFactory)
    {
        $this->doctrine = $doctrine;
        $this->metadataFactory = $metadataFactory;
    }

    public function getRepository($className)
    {
        return $this->doctrine->getRepository($className);
    }

    public function getClassMetadata($className)
    {
        return $this->doctrine->getManagerForClass($className)->getClassMetadata($className);
    }

    public function getMetadataFactory()
    {
        return $this->metadataFactory;
    }

    public function find($className, $id)
    {
        throw new \Exception(__FILE__);
    }

    public function persist($object)
    {
        throw new \Exception(__FILE__);
    }

    public function remove($object)
    {
        throw new \Exception(__FILE__);
    }

    public function merge($object)
    {
        throw new \Exception(__FILE__);
    }

    public function clear($objectName = null)
    {
        throw new \Exception(__FILE__);
    }

    public function detach($object)
    {
        throw new \Exception(__FILE__);
    }

    public function refresh($object)
    {
        throw new \Exception(__FILE__);
    }

    public function flush()
    {
        throw new \Exception(__FILE__);
    }

    public function initializeObject($obj)
    {
        throw new \Exception(__FILE__);
    }

    public function contains($object)
    {
        throw new \Exception(__FILE__);
    }
};

@antishov
Copy link

Here's an object-manager.php that does not error (meaning it's probably not perfect) with multiple entity managers.

With this, \PHPStan\Rules\Doctrine\ORM\EntityColumnRule is able to report violations for both my entity managers' entities.

<?php

use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\Persistence\Mapping\ClassMetadataFactory;
use Doctrine\Persistence\ObjectManager;

require __DIR__.'/../config/bootstrap.php';

$kernel = new \App\Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$kernel->boot();

$doctrine = $kernel->getContainer()->get('doctrine');

$metadataFactory = new class($doctrine) implements ClassMetadataFactory
{
    private Registry $doctrine;

    public function __construct(Registry $doctrine)
    {
        $this->doctrine = $doctrine;
    }

    public function getAllMetadata()
    {
        $all = [];

        foreach ($this->doctrine->getManagers() as $manager) {
            $all = array_merge($all, $manager->getMetadataFactory()->getAllMetadata());
        }

        return $all;
    }

    public function getMetadataFor($className)
    {
        return $this->doctrine->getManagerForClass($className)->getClassMetadata($className);
    }

    public function isTransient($className)
    {
        $isTransient = true;

        foreach ($this->doctrine->getManagers() as $manager) {
            $isTransient = $isTransient && $manager->getMetadataFactory()->isTransient($className);
        }

        return $isTransient;
    }

    public function hasMetadataFor($className)
    {
        $hasMetadata = false;

        foreach ($this->doctrine->getManagers() as $manager) {
            $hasMetadata = $hasMetadata || $manager->getMetadataFactory()->hasMetadataFor($className);
        }

        return $hasMetadata;
    }

    public function setMetadataFor($className, $class)
    {
        throw new \Exception(__FILE__);
    }
};

return new class($doctrine, $metadataFactory) implements ObjectManager
{
    private Registry $doctrine;
    private ClassMetadataFactory $metadataFactory;

    public function __construct(Registry $doctrine, ClassMetadataFactory $metadataFactory)
    {
        $this->doctrine = $doctrine;
        $this->metadataFactory = $metadataFactory;
    }

    public function getRepository($className)
    {
        return $this->doctrine->getRepository($className);
    }

    public function getClassMetadata($className)
    {
        return $this->doctrine->getManagerForClass($className)->getClassMetadata($className);
    }

    public function getMetadataFactory()
    {
        return $this->metadataFactory;
    }

    public function find($className, $id)
    {
        throw new \Exception(__FILE__);
    }

    public function persist($object)
    {
        throw new \Exception(__FILE__);
    }

    public function remove($object)
    {
        throw new \Exception(__FILE__);
    }

    public function merge($object)
    {
        throw new \Exception(__FILE__);
    }

    public function clear($objectName = null)
    {
        throw new \Exception(__FILE__);
    }

    public function detach($object)
    {
        throw new \Exception(__FILE__);
    }

    public function refresh($object)
    {
        throw new \Exception(__FILE__);
    }

    public function flush()
    {
        throw new \Exception(__FILE__);
    }

    public function initializeObject($obj)
    {
        throw new \Exception(__FILE__);
    }

    public function contains($object)
    {
        throw new \Exception(__FILE__);
    }
};

works perfect for me

@VincentLanglet
Copy link
Contributor

Hi, I have a project using both ORM and ODM and encountered the same issue.
Does someone has a workaround for this situation ?

I tried a phpstan-loader, this way:

$doctrineORM   = $kernel->getContainer()->get('doctrine');
$doctrineMongo = $kernel->getContainer()->get('doctrine_mongodb');

// Workaround from https://github.com/phpstan/phpstan-doctrine/issues/53

$metadataFactory = new class($doctrineORM, $doctrineMongo) implements ClassMetadataFactory
{
    private Registry $doctrineORM;

    private ManagerRegistry $doctrineMongo;

    public function __construct(Registry $doctrineORM, ManagerRegistry $doctrineMongo)
    {
        $this->doctrineORM   = $doctrineORM;
        $this->doctrineMongo = $doctrineMongo;
    }

    public function getAllMetadata()
    {
        $all = [];

        foreach ($this->doctrineORM->getManagers() as $manager)
        {
            $all = array_merge($all, $manager->getMetadataFactory()->getAllMetadata());
        }

        foreach ($this->doctrineMongo->getManagers() as $manager)
        {
            $all = array_merge($all, $manager->getMetadataFactory()->getAllMetadata());
        }

        return $all;
    }

    public function getMetadataFor($className)
    {
        if ($this->doctrineORM->getManagerForClass($className) !== null)
        {
            return $this->doctrineORM->getManagerForClass($className)->getClassMetadata($className);
        }

        if ($this->doctrineMongo->getManagerForClass($className) !== null)
        {
            return $this->doctrineMongo->getManagerForClass($className)->getClassMetadata($className);
        }

        throw new \Exception(__FILE__);
    }

    public function isTransient($className)
    {
        foreach ($this->doctrineORM->getManagers() as $manager)
        {
            if ($manager->getMetadataFactory()->isTransient($className))
            {
                return true;
            }
        }

        foreach ($this->doctrineMongo->getManagers() as $manager)
        {
            if ($manager->getMetadataFactory()->isTransient($className))
            {
                return true;
            }
        }

        return false;
    }

    public function hasMetadataFor($className)
    {
        foreach ($this->doctrineORM->getManagers() as $manager)
        {
            if ($manager->getMetadataFactory()->hasMetadataFor($className))
            {
                return true;
            }
        }

        foreach ($this->doctrineMongo->getManagers() as $manager)
        {
            if ($manager->getMetadataFactory()->hasMetadataFor($className))
            {
                return true;
            }
        }

        return false;
    }

    public function setMetadataFor($className, $class): void
    {
        throw new \Exception(__FILE__);
    }
};

return new class($doctrineORM, $doctrineMongo, $metadataFactory) implements ObjectManager
{
    private Registry $doctrineORM;

    private ManagerRegistry $doctrineMongo;

    private ClassMetadataFactory $metadataFactory;

    public function __construct(Registry $doctrineORM, ManagerRegistry $doctrineMongo, ClassMetadataFactory $metadataFactory)
    {
        $this->doctrineORM     = $doctrineORM;
        $this->doctrineMongo   = $doctrineMongo;
        $this->metadataFactory = $metadataFactory;
    }

    public function getRepository($className)
    {
        if ($this->doctrineORM->getManagerForClass($className) !== null)
        {
            return $this->doctrineORM->getManagerForClass($className)->getRepository($className);
        }

        if ($this->doctrineMongo->getManagerForClass($className) !== null)
        {
            return $this->doctrineMongo->getManagerForClass($className)->getRepository($className);
        }

        throw new \Exception(__FILE__);
    }

    public function getClassMetadata($className)
    {
        if ($this->doctrineORM->getManagerForClass($className) !== null)
        {
            return $this->doctrineORM->getManagerForClass($className)->getClassMetadata($className);
        }

        if ($this->doctrineMongo->getManagerForClass($className) !== null)
        {
            return $this->doctrineMongo->getManagerForClass($className)->getClassMetadata($className);
        }

        throw new \Exception(__FILE__);
    }

    public function getMetadataFactory()
    {
        return $this->metadataFactory;
    }

    public function find($className, $id): ?object
    {
        throw new \Exception(__FILE__);
    }

    public function persist($object): void
    {
        throw new \Exception(__FILE__);
    }

    public function remove($object): void
    {
        throw new \Exception(__FILE__);
    }

    public function merge($object): object
    {
        throw new \Exception(__FILE__);
    }

    public function clear($objectName = null): void
    {
        throw new \Exception(__FILE__);
    }

    public function detach($object): void
    {
        throw new \Exception(__FILE__);
    }

    public function refresh($object): void
    {
        throw new \Exception(__FILE__);
    }

    public function flush(): void
    {
        throw new \Exception(__FILE__);
    }

    public function initializeObject($obj): void
    {
        throw new \Exception(__FILE__);
    }

    public function contains($object): bool
    {
        throw new \Exception(__FILE__);
    }
};

By following the previous suggestion, and expecting phpstan to use the orm or odm according to the entity/document.
But I ended up with errors like

  324    Call to an undefined method Doctrine\ORM\QueryBuilder::field().                                                                    
  324    Method Doctrine\ORM\EntityRepository<App\Document\UserMd5Document>::createQueryBuilder() invoked with 0 parameters, 1-2 required.

Am I doing something wrong in my object loader or something should/could be changed in the phpstan-doctrine extension implementation in order to allow such an object loader implementation.

@ondrejmirtes
Copy link
Member

Most phpstan-doctrine features will work without providing objectManagerLoader in phpstan-doctrine 1.2.0 thanks to: #253

It should solve this use-case too.

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests