Symfony2 / Doctrine - changing all requests

Is it possible to run all doctrine requests using some kind of walker so that I can change the request based on the current user credentials? Ideally, I would not have to explicitly call setHint for a custom walker for each request, as this would limit my ability to pass the current SecurityContext to the walker.

In addition, I would prefer not to use the Doctrine filter, since I cannot change the conditions for connecting to the filters, and I would have to use the "IN" clause, which would seriously affect performance

I am currently using a service that modifies QueryBuilder based on user credentials, but this is getting tedious, since I need to call the service every time I create a new QueryBuilder, and it is even more painful when Repositories come into play (since I You will need to deploy the service to each repository that needs to modify the request.

I hope I explained this quite clearly. Rate any feedback!

+4
source share
2 answers

You can write a custom AST Walker and configure the application to use this walker for all queries using the defaultQueryHint (new Doctrine 2.5 feature) configuration option:

 <?php /** @var \Doctrine\ORM\EntityManager $em */ $em->getConfiguration()->setDefaultQueryHint( Query::HINT_CUSTOM_TREE_WALKERS, ['YourWalkerFQClassName'] ) 
+1
source

I think I solved my problem. If someone else has a more elegant way to achieve these results, feel free to explain. To change all my queries, I created my own EntityManager and a custom EntityRepository.

In my custom EntityManager, I overwrote 2 methods. create () and getRepository ()

 public static function create($conn, Configuration $config, EventManager $eventManager = null) { if ( ! $config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } switch (true) { case (is_array($conn)): $conn = \Doctrine\DBAL\DriverManager::getConnection( $conn, $config, ($eventManager ?: new EventManager()) ); break; case ($conn instanceof Connection): if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { throw ORMException::mismatchedEventManager(); } break; default: throw new \InvalidArgumentException("Invalid argument: " . $conn); } return new MyCustomEntityManager($conn, $config, $conn->getEventManager()); } 

The only thing that has changed in this method is that I return my own EntityManger ( MyCustomEntityManager ). Then I overlaid the getRepository method as follows:

 public function getRepository($entityName) { $entityName = ltrim($entityName, '\\'); if (isset($this->repositories[$entityName])) { return $this->repositories[$entityName]; } $metadata = $this->getClassMetadata($entityName); $repositoryClassName = $metadata->customRepositoryClassName; if ($repositoryClassName === null) { $repositoryClassName = "Acme\DemoBundle\Doctrine\ORM\MyCustomEntityRepository"; } $repository = new $repositoryClassName($this, $metadata); $this->repositories[$entityName] = $repository; return $repository; } 

Here I only changed one line. Instead of relying on the DBAL configuration to restore the default value of $ repositoryClassName, I specified my own default repository Acme \ DemoBundle \ Doctrine \ ORM \ MyCustomEntityRepository .

Once you have created your own EntityRepository, the sky is the limit. You can embed services in the repository (I currently use the JMS Di annotations described below) or perform custom actions against QueryBuilder in the createQueryBuilder method, for example:

 use JMS\DiExtraBundle\Annotation as DI; class MyCustomEntityRepository extends EntityRepository { private $myService; public function createQueryBuilder($alias) { $queryBuilder = parent::createQueryBuilder($alias); /** INSERT CUSTOM CODE HERE **/ return $queryBuilder; } /** * @DI\InjectParams({ * "myService" = @DI\Inject("my_service_id") * }) */ public function setMyService(MyServiceInterface $myService) { $this->myService = $myService; } } 

Once you have created your own EntityRepository, you should have all of your repositories that need this custom functionality, expanding MyCustomEntityRepository. You can even take it one step further and create your own QueryBuilder for further expansion.

0
source

All Articles