Access to inherit class attribute from DQL in Symfony2 - symfony

I have an abstract class Product and inherited class ProductWithRecurrency:
/**
* #ORM\Table(name= "product")
* #ORM\Entity(repositoryClass="Acme\StoreBundle\Entity\Repositories\ProductRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="product_kind_id", type="integer")
* #ORM\DiscriminatorMap({"1" = "ProductFoo", "2" = "ProductWithRecurring"})
*/
abstract class Product
{
}
/**
*
* #ORM\Table(name="product_with_recurring")
* #ORM\Entity( repositoryClass ="Acme\StoreBundle\Entity\Repositories\ProductRepository")
*/
class ProductWithRecurring extends Product
{
/**
* #var Recurring $recurring
*
* #ORM\JoinColumn(name="recurring_id", referencedColumnName="id", nullable=false)
*/
protected $recurring;
}
I need to get some mixed Products and have "Recurring" Entity information when Product is instance of ProductWithRecurring. I have a method in ProductRepository with this dql:
$dql = "SELECT p product
FROM Acme\StoreBundle\Entity\Product p
LEFT JOIN p.recurring rc
WHERE p.some_conditions";
Obviously get this exception:
[Semantical Error] line 0, col 1182 near 'rc
': Error: Class Acme\StoreBundle\Entity\Product has no association named recurring
Do I should add complexity to query or I have a conceptual error? (I'm no expert in Symfony and less in Doctrine).
There may be errors in the code, I've simplified it to isolate the problem.
My english is not so good, I hope you understand me, thanks!

You should be able to access all of the Product atributes in Product ProductWithRecurring.
Using code below does not work? I do not quite understand what you'd like to get as a result
$dql = "SELECT p
FROM Acme\StoreBundle\Entity\ProductWithRecurring p
WHERE p.some_conditions";

Related

Merge two queries with DQL

I have my main entity poi that has two OneToOne relation with my two other entities people and places.
App/Entity/People.php
class People
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="App\Entity\Poi", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $poi;
App/Entity/Places.php
class Places
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="App\Entity\Poi", cascade={"persist", "remove"})
*/
private $poi;
Now I need to get the peopleand places in the same array or something. I got that by merging two queries :
$query = $entityManager->createQuery('select p from App:People p'); //same for places then merge in array...
Q : Is there a way to get the same result with one DQL query? (especially if the entities don't have the same columns).
To simply get all People and Places in one array you can go with:
$query = $entityManager->createQuery('select people, places from App:People people, App:Places places');
I guess you will want to fetch them for a given Poi, in that case if you only have the poi id you can try this:
$query = $entityManager
->createQuery('select people, places from App:People people, App:Places places where people.poi = :poi and places.poi = :poi')
->setParameter('poi', $poiId)
;
Naturally, if you have a Poi entity object at your disposal, you can simply do
$peopleAndPlaces = [$poi->getPeople(), $poi->getPlaces()]
Note that in order for above code to work you have to add those methods to respective entity classes and make sure the relations with Poi are bidirectional
If you for whatever reason often need to get that array and you have a Poi entity object, it might be a good idea to add a method to the Poi class
class Poi
{
...
public function getPeopleAndPlaces()
{
return [$this->getPeople(), $this->getPlaces()];
}
and then call $poi->getPeopleAndPlaces() when needed.

Error when I try to make a ManyToMany relation in Symfony 2

I want to make a ManyToMany relation in Doctrine with Symfony 2 between a group and an user : many users can be in many groups and many groups can have many users.
Then in my entities, i do this :
Groupe.php
/**
* Many Groups have Many clients.
* #ORM\ManyToMany(targetEntity="Utilisateurs\UtilisateursBundle\Entity\Client", mappedBy="groupe")
* #ORM\JoinTable(name="client_groupe")
*/
private $clients;
/**
* Get clients
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getClients()
{
return $this->clients;
}
Client.php
/**
* #ORM\ManyToMany(targetEntity="Ecommerce\EcommerceBundle\Entity\Groupe", inversedBy="clients")
* #ORM\JoinTable(name="client_groupe",
* joinColumns={#ORM\JoinColumn(name="client_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="groupe_id", referencedColumnName="id")}
* )
*/
private $groupe;
but when I call the getClients() function on my entity $groupe, following error occured :
FROM client t0 WHERE client_groupe.groupe_id = ?' with params ["2"]:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'client_groupe.groupe_id' in 'where clause'
It doesn't add the client_groupe table in the from clause.
Someone can help me ?
No need to add client_groupe table in from clause. Try after removing * #ORM\JoinTable(name="client_groupe") from Groupe.php. Have a look at following working example of ManyToMany relationship scenario.
Groupe.php
/**
* Many Groups have Many clients
* #ORM\ManyToMany(targetEntity="Utilisateurs\UtilisateursBundle\Entity\Client", mappedBy="groupe")
*/
private $clients;
Client.php
/**
* #ORM\ManyToMany(targetEntity="Ecommerce\EcommerceBundle\Entity\Groupe", inversedBy="clients")
* #ORM\JoinTable(name="client_groupe",
* joinColumns={#ORM\JoinColumn(name="client_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="groupe_id", referencedColumnName="id")}
* )
*/
private $groupe;
client_id and groupe_id is fields of client_groupe table. Generate Getter and setter using doctrine command and update database using bin/console doctrine:schema:update --force command.

Symfony entities without relational

I work with Symfony2 and Doctrine and I have a question regarding entities.
In a performance worries, I'm wondering if it is possible to use an entity without going all the associations?
Currently, I have not found another way to create a model inheriting the class with associations and associations specify NULL in the class that inherits.
thank you in advance
OK, a little detail, it's for a API REST (JSON).
This is my class :
/**
* Offerequipment
*
* #ORM\Table(name="offer_equipment")
* #ORM\Entity(repositoryClass="Charlotte\OfferBundle\Repository\Offerequipment")
*/
class Offerequipment
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Charlotte\OfferBundle\Entity\Offer")
* #ORM\JoinColumn(name="offer_id", referencedColumnName="id")
*/
private $offer;
/**
* #ORM\ManyToOne(targetEntity="Charlotte\ProductBundle\Entity\Equipment")
* #ORM\JoinColumn(name="equipment_id", referencedColumnName="id")
*/
private $equipment;
/**
* #VirtualProperty
*
* #return String
*/
public function getExample()
{
return $something;
}
and with QueryBuilder method, i can't get my virtual properties or getters.
Thanks for your help :)
Look at Serialization.
By serialising your entities, you can choose to exclude or expose a property of an entity when you render it.
Look at the Symfony built-in Serializer and/or JMSSerializer.
Otherwise, you can use QueryBuilder and DQL to choose what fields you want to fetch in your queries.
Like this, you can make your own find method in the Repository of your entities.
// src/AcmeBundle/Repository/FooRepository
class FooRepository extends \Doctrine\ORM\EntityRepository
// ...
public function find($id) {
$queryBuilder = $this->createQueryBuilder('e')
->select('e.fieldA', 'e.fieldB') // selected fields
->where('e.id = :id') // where statement on 'id'
->setParameter('id', $id);
$query = $queryBuilder->getQuery();
$result = $query->getResult();
}
// ...
}
Don't forget define the Repository in the corresponding Entity.
/**
* Foo.
*
* #ORM\Entity(repositoryClass="AcmeBundle\Repository\FooRepository")
*/
class Foo
{
// ...
}
By default Doctrine will not automatically fetch all of the associations in your entities unless you specifically each association as EAGER or unless you are using a OneToOne association. So if you are looking to eliminate JOINs, you can just use Doctrine in its default state and it won't JOIN anything automatically.
However, you this will not alleviate all of your performance concerns. Say, for example, you are displaying a list of 50 products in your application on a single page and you want to show their possible discounts, where discounts are an association on your product entity. Doctrine will create 50 additional queries just to retrieve the discount data unless you explicitly join the discount entity in your query.
Essentially, the Symfony profiler will be your friend and show you when you should be joining entities on your query - don't just think that because you aren't joining associations automatically that your performance will always be better.
Finally, after many days, I've found the solution to select only one entity.
VirtualProperties are found :)
public function findAllByOffer($parameters)
{
$queryBuilder = $this->createQueryBuilder('oe');
$queryBuilder->select('oe, equipment');
$queryBuilder->join('oe.equipment', 'equipment');
$result = $queryBuilder->getQuery()->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)->getResult();
return $result;
}

Doctrine n:m relation Undefined index: joinColumns in BasicEntityPersister.php

My question is strongly related to this one Undefined index: inverseJoinColumns while trying to define ManyToMany relationship between two entities
I am trying to find all the books which have no section. ->findBy(array("section"=>null)
Here is my Entity config:
EditedBooks
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Sections", inversedBy="editedBook")
* #ORM\JoinTable(name="edited_book_has_section",
* joinColumns={
* #ORM\JoinColumn(name="edited_book_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="section_id", referencedColumnName="id")
* }
* )
*/
private $section;
Here is my Entity config:
Sections
/**
* Bidirectional (INVERSE SIDE)
*
* #ORM\ManyToMany(targetEntity="EditedBooks", mappedBy="section")
*/
private $editedBook;
The Error that I am getting
Undefined index: joinColumns in BasicEntityPersister.php
I tryied it also with only
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Sections", inversedBy="editedBook")
* #ORM\JoinTable(name="edited_book_has_section")
*/
or switching the definition but then I receive this error
You cannot search for the association field '\Entity\EditedBooks#section', because it is the inverse side of an association. Find methods only work on owning side associations.
Workaround:
Today I tried to fix my problem with the querybuilder in my editedBooksRepository
$query = $qb->select('books')
->from('Bundle:EditedBooks', 'books')
->leftJoin('books.section', 'sec')
->addSelect('COUNT(sec.id) AS sec_count')
->andWhere('sec_count = 0');
But I receved the following error:
An exception occurred while executing 'SELECT e0_.id AS id0, e0_.doi
AS doi1, e0_.isbn_print AS isbn_print2, e0_.isbn_electronic AS
isbn_electronic3, e0_.publication_date AS publication_date4,
e0_.price_print AS price_print5, e0_.price_electronic AS
price_electronic6, e0_.summary AS summary7, e0_.title AS title8,
e0_.ongoing AS ongoing9, e0_.pages AS pages10, e0_.illustrations AS
illustrations11, e0_.entry_date AS entry_date12, e0_.google_id AS
google_id13, e0_.specialIssue_comment AS specialIssue_comment14,
e0_.deleted AS deleted15, e0_.specialIssue_id AS specialIssue_id16,
COUNT(s1_.id) AS sclr17, e0_.book_series_id AS book_series_id18,
e0_.copyright_id AS copyright_id19, e0_.publisher_id AS publisher_id20
FROM edited_books e0_ LEFT JOIN edited_book_has_section e2_ ON e0_.id
= e2_.editedbooks_id LEFT JOIN sections s1_ ON s1_.id = e2_.sections_id WHERE sclr17 = 0':
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sclr17' in
'where clause'
but to me it seems like sclr17 exists, am I missing something?
The ugly Workaround
I know it is not the right thing to do but sometimes a man has to to what a man has to do:
$noSection = new Sections();
$noSection->setTitle("Sectionless");
//add all the books
$noSection->setEditedBook(new ArrayCollection($books));
//remove the assigned ones
foreach($sections as $section){
$sBooks = $section->getEditedBook();
foreach($sBooks as $b){
$noSection->removeEditedBook($b);
}
}
With the dirty fix it is now working but I am glad for any other solution.
Here is a working example
class Audio
{
/**
* #ORM\ManyToMany(targetEntity="Acme\MyBundle\Entity\Groupe",inversedBy="audios")
*/
private $groupes;
class Groupe
{
/**
* #ORM\ManyToMany(targetEntity="Acme\MyBundle\Entity\Audio",mappedBy="groupes")
*/
private $audios;
Notice how the mappedby and inversedby, as well at the attributes have an "s" at the end. (Groupe => private $groupe s ). Maybe it will help you
Can't you just check with null?
$query = $qb->select('books')
->from('Bundle:EditedBooks', 'books')
->leftJoin('books.section', 'sec')
->where('sec IS NULL');

Doctrine not found entity id

i have a problem mapping entities in Doctrine 2 (with Symfony2). Symfony says that error is in Perfil entity, but the Doctrine section profiler says that the error is en Funcion entity.
This is the error (on the browser):
The column id must be mapped to a field in class
AppsManantiales\CommonBundle\Entity\Perfil since it is referenced by a
join column of another class.
But, in the profiler:
AppsManantiales\CommonBundle\Entity\Funcion: The referenced column
name 'id' has to be a primary key column on the target entity class
'AppsManantiales\CommonBundle\Entity\Funcion'. The referenced column
name 'id' has to be a primary key column on the target entity class
'AppsManantiales\CommonBundle\Entity\Perfil'.
This is the relation er:
The Perfil entity, basically is:
class Perfil implements RoleInterface{
/**
* #ORM\Id
* #ORM\Column(type="integer", length=10)
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $idperfil;
/**
* #ORM\ManyToMany(targetEntity="Funcion", mappedBy="perfiles")
* #ORM\JoinTable(name="perfil_funcion",
* joinColumns={#ORM\JoinColumn(name="perfil", referencedColumnName="idperfil")},
* inverseJoinColumns={#ORM\JoinColumn(name="funcion", referencedColumnName="idfuncion")}
* )
*/
protected $funciones;
// More code...
}
The Funcion entity basically is:
class Funcion {
/**
* #ORM\Id
* #ORM\Column(type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $idfuncion;
/**
* #ORM\ManyToMany(targetEntity="Perfil", inversedBy="funciones")
*/
protected $perfiles;
// More code...
}
Any ideas ? Thanks !
I think by default Doctrine relies on the convention that all primary keys in entities are represented by an attribute called $id. Two solutions :
Rename your primary keys from $idperfil and $idfuncion to $id (which I recommend);
Explicit the join criterion on your Funcion object on the $perfiles property:
* #ORM\JoinTable(name="perfil_function"),
* joinColumns={#ORM\JoinColumn(name="funcion", referencedColumnName="idfuncion")},
* inverseJoinColumns={#ORM\JoinColumn(name="perfil", referencedColumnName="idperfil")}
* )

Resources