I have 2 bundles and i want to override the repository of one of them in the other :
I have a source bundle : SourceBundle.
I have my override bundle : OverrideBundle
First, in OurVendorOverrideBundle.php, I added :
public function getParent()
{
return 'SomeVendorSourceBundle';
}
Then
I wanted to add a custom method for the repository of an entity of SourceBundle.
The source entity is Response.php, and its repository is ResponseRepository.php
So i did :
<?php
namespace OurVendor\OverrideBundle\Repository;
use Doctrine\ORM\EntityRepository;
use SomeVendor\SourceBundle\Repository\ResponseRepository as BaseRepository;
class ResponseRepository extends BaseRepository
{
/**
*
* #return array
*/
public function getQueryExerciseAllResponsesForAllUsers($exoId)
{
$qb = $this->createQueryBuilder('r');
$qb->join('r.paper', 'p')
->join('p.exercise', 'e')
->where('e.id = ?1')
->andWhere('p.interupt = ?2')
->setParameters(array(1 => $exoId, 2 => 0));
return $qb->getQuery();
}
}
If i dont set the Entity in the OverrideBundle i have this error :
The autoloader expected class "CPASimUSante\ExoverrideBundle\Entity\Response" to be defined in file "/home/www/myproject/vendor/ourvendor/override-bundle/OurVendor/OverrideBundle/Entity/Response.php". The file was found but the class was not in it, the class name or namespace probably has a typo.
The SourceBundle entity is :
<?php
namespace SomeVendor\SourceBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* SomeVendor\SourceBundle\Entity\Response
*
* #ORM\Entity(repositoryClass="SomeVendor\SourceBundle\Repository\ResponseRepository")
* #ORM\Table(name="source_response")
*/
class Response
{
...
}
So i add the Entity in the OverrideBudle :
<?php
namespace OurVendor\OverrideBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use SomeVendor\SourceBundle\Entity\Response as BaseEntity;
/**
* SomeVendor\SourceBundle\Entity\Response
*
* #ORM\Entity(repositoryClass="OurVendor\OverrideBundle\Repository\ResponseRepository")
* #ORM\Table(name="override_response")
*/
class Response extends BaseEntity
{
public function __construct()
{
parent::__construct();
}
}
But then i have this error :
An exception occurred while executing 'SELECT u0_.id AS id0, u0_.ip AS ip1, u0_.mark AS mark2, u0_.nb_tries AS nb_tries3, u0_.response AS response4, u0_.paper_id AS paper_id5, u0_.interaction_id AS interaction_id6 FROM ujm_exoverride_response u1_ INNER JOIN ujm_paper u2_ ON u0_.paper_id = u2_.id INNER JOIN ujm_exercise u3_ ON u2_.exercise_id = u3_.id WHERE u3_.id = ? AND u2_.interupt = ?' with params ["1", 0]:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'u0_.id' in 'field list'
This seems that fields in the table are not found. So i changed to
<?php
namespace OurVendor\OverrideBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use SomeVendor\SourceBundle\Entity\Response as BaseEntity;
/**
* SomeVendor\SourceBundle\Entity\Response
*
* #ORM\Entity(repositoryClass="OurVendor\OverrideBundle\Repository\ResponseRepository")
* #ORM\Table(name="source_response")
*/
class Response extends BaseEntity
{
public function __construct()
{
parent::__construct();
}
}
And it worked.
...But when i reinstalled the bundle, to test if everything was ok i had this fatal error stating that source_response is already defined (which is, indeed).
So what can i do then ?
I have also read that i can't override an entity unless the source extends MappedSuperclass, in my case, it doesn't.
But i am doomed if i only want to override its repository ? Is it possible ? If then, what is the right way ?
If i remove altogether the annotation for the override entity, i have :
Class "OurVendor\OverrideBundle\Entity\Response" sub class of "SomeVendor\SourceBundle\Entity\Response" is not a valid entity or mapped super class.
500 Internal Server Error - MappingException
Doctrine mapping in another bundles can be overriden on entity class metadata loading.
EventListener
<?php
namespace Lol\RandomBundle\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class ClassMetadataListener
{
/**
* Run when Doctrine ORM metadata is loaded.
*
* #param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
if ('AnotherLol\AnotherRandomBundle\Entity\Response' === $classMetadata->name) {
// Do whatever you want...
$classMetadata->customRepositoryClassName = 'ThirdLol\SomeBundle\Repository\NewResponseRepository';
}
}
}
Service configuration
services:
lol.random.listener.class_metadata:
class: Lol\RandomBundle\EventListener\ClassMetadataListener
tags:
- { name: doctrine.event_listener, event: loadClassMetadata }
Related
I have an abstract class:
/**
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({
* "LegalInsuranceProof" = "LegalInsuranceProofDocument",
* "SalesReceipt" = "SalesReceiptDocument"
* })
* #ORM\HasLifecycleCallbacks()
* #ORM\Table(name="document_abstract")
* #ORM\Entity(repositoryClass="App\Repository\DocumentRepository")
*/
abstract class AbstractDocument implements CreateFolderInterface
{
.
.
.
}
and the class, that extends this abstract class:
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
* #ORM\Table(name="document_sales_receipt")
*/
class SalesReceiptDocument extends AbstractDocument
{
.
.
.
}
In the repo, I have defined the method getReviewListPaginator:
class DocumentRepository extends ServiceEntityRepository {
use PaginatorTrait;
public function __construct(RegistryInterface $registry) {
parent::__construct($registry, AbstractDocument::class);
}
public function getReviewListPaginator($limit, $offset) {
$this->assertQueryParameters($offset, $limit, "asc");
$qb = $this
->createQueryBuilder('d')
->select('PARTIAL d.{id, pageCount}')
->innerJoin('d.case', 'c')
->addSelect('PARTIAL c.{id}')
->setFirstResult($offset)
->setMaxResults($limit);
return new Paginator(
$qb->getQuery()->setHydrationMode(Query::HYDRATE_ARRAY),
true
);
}
}
If I do
$this->em->getRepository(AbstractDocument::class)->getReviewListPaginator(5,2);
the method getReviewListPaginator is called.
But If I do
$paginator = $this->em->getRepository(SalesReceiptDocument::class)->getReviewListPaginator(5,2);
I get en error message:
BadMethodCallException : Undefined method 'getReviewListPaginator'. The method name must start with either findBy, findOneBy or countBy!
But why? Should I define a repo for the SalesReceiptDocument entity, that extends the App\Repository\DocumentRepository?
I don't think the Repository are extended by default.
I think you need to do a SalesReceiptReporsitory that explicitly exteands your DocumentRepository
And add the repositoryClass options to your #Entity on SalesReceiptDocument.
Your #Entity annotations do not have the repository specified, change them to:
#Entity(repositoryClass="..namespace..\DocumentRepository")
See the #Entity documentation.
Edit 1:
I just noticed your AbstractDocument has duplicate #Entity annotation, you can just delete the empty one
Edit 2:
To select different document types you need separate repositories, to keep your code simple and non-repeating, you can use the $_entityName attribute of EntityRepository if you are extending it or have your own private attribute that would indicate the entity name for a repository and then use this entity name in the getReviewListPaginator to dynamically query the type of entity you want.
As far as I can tell, you cannot achieve this without having separate repositories for each type of document - even if each is empty, just extending the base repository and doing the parametrized query building as I described.
I try to create default repository in my Symfony 3. First I created Repository class with method 'findByParentOrderedByName'. In next step I added in Entity line:
* #ORM\Entity(repositoryClass="AppBundle\Repository\ChildRepository")
Unfortunelly when I try to run findByParentOrderedByName() I get error
Undefined method 'findAllOrderedByName'. The method name must start with either findBy, findOneBy or countBy!
What I make incorrect?
Repository code:
<?php
namespace AppBundle\Entity;
/**
* Child
* #ORM\Entity(repositoryClass="AppBundle\Repository\ChildRepository")
*/
class Child
{
........
}
To use custom repository class properly, firstly repository class name must be defined in entity class.
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\ChildRepository")
*/
class Child
{
}
Then repository class created as like this:
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class ChildRepository extends EntityRepository
{
/**
* #return Child[]
*/
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery('SELECT * c FROM AppBundle:Child c ORDERED BY c.name ASC')
->getResult();
}
}
I try to follow this tutorial for the pagination: https://knpuniversity.com/screencast/symfony-rest3/pagerfanta-pagination
For the moment I have installed the white-october/pagerfanta-bundle, and when I made my user repository as following :
<?php
// src/UsersBundle/Repository/UserRepository.php
namespace UsersBundle\Repository;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository {
public function findAllQueryBuilder() {
return $this->createQueryBuilder('user');
}
}
and in my controller action I did this:
<?php
// src/UsersBundle/Controller/UsersController.php
namespace UsersBundle\Controller;
// use statements ...
/**
* Class UsersController
*
* #package UsersBundle\Controller
*
* #Rest\RouteResource("user", pluralize=false)
* #Rest\NamePrefix( "api_v1_" )
*/
class UsersController extends FOSRestController implements ClassResourceInterface {
// ...
/**
* Responsible to list all the registered users.
*
* #Rest\QueryParam(name="page", default="1", requirements="\d+",nullable=true)
*
* #return array|\Traversable
*/
public function getListAction( ParamFetcher $param_fetcher ) {
if ( ! $this->isGranted( 'ROLE_ADMIN' ) ) {
throw new UnauthorizedHttpException( 'You do not have sufficient permission to access this resource' );
}
$qb = $this->getDoctrine()
->getRepository('UsersBundle\Repository\UserRepository')
->findAllQueryBuilder();
$adapter = new DoctrineORMAdapter( $qb );
$users = $this->user_manager->findUsers();
return $users;
}
// ...
}
I got this output:
{"code":500,"message":"The class 'UsersBundle\\Repository\\UserRepository' was not found in the chain configured namespaces UsersBundle\\Entity, FOS\\UserBundle\\Model"}
Anyone knows what that output means? Unfortunately I am totally new to Symfony, and I cannot understand what is the issue for this output.
$qb = $this->getDoctrine()
->getRepository('UsersBundle\Repository\UserRepository')
->findAllQueryBuilder();
You should find you Repository throug your entity, so something like this
$qb = $this->getDoctrine()
->getRepository('User:class')
->findAllQueryBuilder();
Doc: https://symfony.com/doc/current/doctrine.html#fetching-objects-from-the-database
And in your User entity you should have something like this
/**
* #ORM\Table(name="User")
* #ORM\Entity(repositoryClass=UserRepository::class)
*/
class User {
...
I'm trying to work with Entity Repository to write my custom functions.
I have an Entity and his Repository generated from yaml file
Yaml file
Bluesys\WeekupBundle\Entity\Event:
type: entity
repositoryClass: Bluesys\WeekupBundle\Repository\Event
fields:
id:
id: true
type: integer
generator:
strategy: AUTO
...
Entity code automatically generated
namespace Bluesys\WeekupBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Event
*/
class Event
{
/**
* #var integer
*/
private $id;
...
}
Repository code automatically generated
I juste wrote the function isHidden
namespace Bluesys\WeekupBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* Event
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class Event extends EntityRepository
{
/**
* isHidden
*
* #return bool
*/
public function isHidden()
{
return true;
}
}
The Controller code
namespace Bluesys\WeekupBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Bluesys\WeekupBundle\Event\Event;
...
class TimelineController extends Controller
{
public function testAction(){
$repository = $this->getDoctrine()->getManager()->getRepository('BluesysWeekupBundle:Event');
$event = $repository->findOneById( 73 );
return $this->render('BluesysWeekupBundle::test.html.twig', array( 'event' => $event ));
}
...
And the view code
{{ event.isHidden }}
I get this error :
Method "isHidden" for object "Bluesys\WeekupBundle\Entity\Event" does not exist in BluesysWeekupBundle::test.html.twig at line 1
Can somebody help me by telling me what is missing ?
Repository classes are used only for selecting/fetching data. They are not the part of entity/object.
If you really want to call isHidden method by repository you can acheive this by passing the whole repository to template (return $this->render('BluesysWeekupBundle::test.html.twig', array( 'event' => $repository ));), but this is very bad idea.
Instead you can put isHidden() method into your entity class and call it as event.isHidden..
User Entity :
namespace Core\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
* #ORM\Entity(repositoryClass="Core\UserBundle\Entity\UserRepository")
* #ORM\Table(name="user")
*/
class User
{
}
User Repository :
<?php
# src/Core/UserBundle/Entity/UserRepository.php
namespace Core\UserBundle\Entity;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
public function example()
{
return "hello word";
}
}
Controller :
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('CoreUserBundle:User');
$repo->example();
Note : get_class($repo) => Doctrine\ORM\EntityRepository
The error:
Error Message : Undefined method 'example'. The method name must start with either findBy or findOneBy!
Try with this
$repo = $em->getRepository('UserBundle:User');