Doctrine2 Get Table Relations - doctrine-orm

I need to get one/many To one/many relations informations from an entity with Doctrine2
With Doctrine1 I can do :
Doctrine::getTable('Article')->getRelations();
How to do it with Doctrine2 ?

You can use Doctrine\ORM\Mapping\ClassMetadataFactory for this.
$metaData = $em->getMetadataFactory()->getMetadataFor('your_classname')

Related

Define unique columns on ManyToMany in Doctrine

I'm trying to add unique columns on a pivot table created via a ManyToMany association.
I found this page of the documentation explaining how to generate a database unique constraint on some columns with this example:
/**
* #Entity
* #Table(name="ecommerce_products",uniqueConstraints={#UniqueConstraint(name="search_idx", columns={"name", "email"})})
*/
class ECommerceProduct
{
}
But this only works if I create the pivot table via a third entity and, in my case, I created the pivot table using a ManyToMany relation (in the same fashion as this code).
Is there a way to add unique columns on pivot table while still using ManyToMany or do I need to rely on a third entity?
While #Table annotation proposes a uniqueConstraints option, #JoinTable does not. Thus, if you want to add a unique constraint on your association table, you will have to actually create another entity explicitly.
That being said, the default join table should not need anything more than the default configuration set up by Doctrine. Currently, when adding a ManyToMany association, the join table is composed of two fields and a composite primary key relying on both fields is created.
If your association table only contains the two basic fields referring to both sides of your association (which is necessarily the case if you use #ManyToMany), the composite primary key should be all you need.
Here is the generated SQL for the basic example where a User has a ManyToMany association with Group (from this section of the documentation):
CREATE TABLE users_groups (
user_id INT NOT NULL,
group_id INT NOT NULL,
PRIMARY KEY(user_id, group_id)
) ENGINE = InnoDB;
ALTER TABLE users_groups ADD FOREIGN KEY (user_id) REFERENCES User(id);
ALTER TABLE users_groups ADD FOREIGN KEY (group_id) REFERENCES Group(id);
As you can see, everything is properly set up with a composite primary key which will ensure that there can't be duplicate entries for the couple (user_id, group_id).
Of course there is another alternative, Alan!
If you need a Zero to Zero relationship, the only alternative is defining the unique constraint per each pk in the agregated table, to make doctrine figuring out about zero to zero relationship.
The problem is that Doctrine's people hadn't considered zero to zero relationships, so the only alternative for this is manytomany relationship with one unique constraint per pk.
If you have doubts about final-state of your doctrine implementation of your E-R model, I strongly recommend mysql-workbench-schema-exporter. With this php tool, you can easily export your mysql workbench E-R schema to a Doctrine's working classes schema, so you would be able to easily explore all your alternatives ;-)
Hope this helps

Symfony2 DQL Update query with Many to Many

I have three tables "category", "product" and "product_category".
First two tables are created from two entity Category and Product.
Third table "product_category" is auto generated by framework doctrine console command.
Now I can get (fetch) product relational data (based on category id) from below query, which is fine.
$this->createQueryBuilder('p')
->leftJoin('p.category', 'c')
->select('p')
->where('c.id = :category_id')
->setParameter('category_id', 2)
->getQuery()->getSQL();
But how can I use Many-to-Many relation to Update Data?
I had Tried with several queries but its not working!!!
( I want to update all product status to inactive (2), whose category status is (2 = Inactive).
When doing a query on a table that has children. You can also just fetch the parent item, and doctrine will automatically handle the child objects. If you have a getCategory within the Product entity, it will resolve the category automatically.
Probably what you are looking for is cascading of events. of which is explained within Doctrine 2 ManyToMany cascade

How to get all possible values of entity field in Symfony 2.8 with Doctrine

Let's assume I have entity User with property country. country is just a string and many users can have setted the same country. Then how to get list of all unique countries of all users? I'm using Symfony2.8 with Doctrine.
you need to use the DISTINCT clause: https://www.w3schools.com/sql/sql_distinct.asp
Here is how you can do it from a controller :
$qb = $em->getRepository("MyBundle:Country")->createQueryBuilder("c");
$countries = $qb->select("c")
->distinct(true)
->getQuery()
->getResult();
one liner:
$countries = $em->getRepository("MyBundle:Country")->findBy(array('distinct' => true));
However if i were you i would create a country entity wich is unique and make ManyToOne relationship between User and Country.that would be a much cleaner solution IMO

Prevent multiple SQL querys with model relations

Is it possible to prevent multiple querys when i use django ORM ? Example:
product = Product.objects.get(name="Banana")
for provider in product.providers.all():
print provider.name
This code will make 2 SQL querys:
1 - SELECT ••• FROM stock_product WHERE stock_product.name = 'Banana'
2 - SELECT stock_provider.id, stock_provider.name FROM stock_provider INNER JOIN stock_product_reference ON (stock_provider.id = stock_product_reference.provider_id) WHERE stock_product_reference.product_id = 1
I confess, i use Doctrine (PHP) for some projects. With doctrine it's possible to specify joins when retrieve the object (relations are populated in object, so no need to query database again for get attribute relation value).
Is it possible to do the same with Django's ORM ?
PS: I hop my question is comprehensive, english is not my primary language.
In Django 1.4 or later, you can use prefetch_related. It's like select_related but allows M2M relations and such.
product = Product.objects.prefetch_related('providers').get(name="Banana")
You still get two queries, though. From the docs:
prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python.
As for packing this down into a single query, Django won't do it like Doctrine because it doesn't do that much post-processing of the result set (Django would have to remove all the redundant column data, since you'll get a row per provider and each of these rows will have a copy of all of product's fields).
So if you want to pack this down to one query, you're going to have to turn it around and run the query on the Provider table (I'm guessing at your schema):
providers = Provider.objects.filter(product__name="Banana").select_related('product')
This should pack it down to one query, but you won't get a single product ORM object out of it, instead needing to get the product fields via providers[k].product.
You can use prefetch_related, sometimes in combination with select_related, to get all related objects in a single query: https://docs.djangoproject.com/en/1.5/ref/models/querysets/#prefetch-related

Doctrine join filter

I know conditional filters aren't yet available for queries (as per "26.1.4. Applying Filter Rules to any Query" in the Known Limitations section of the Doctrine2 manual) , so I wanted to ask the experts what their preferred solution to the following problem is:
My site has product objects that each have many reviews. The reviews have a status field. I don't want to unnecessarily pull in reviews that haven't been approved during the automatic association that Doctrine2 does so wonderfully.
My current solution/hack is to use single table inheritance (STI) with a discriminator for "status" and have an ApprovedProductReview extending the ProductReview class based on a status of "APPROVED"
I should add that I am currently simply calling
$em->find('Entities\Product', $pid);
to get my product, and Doctrine2 does all the associations automatically. Should I instead be instantiating a product by providing a DQL query?
What I'd really like is a way to override the magic that Doctrine2 provides based on the annotations, and simply be able to use DQL to lazily get the correct subset of reviews.
Suggestions?
You can use the WITH statement in DQL:
$dql = "SELECT p, r
FROM Entities\Product p
LEFT JOIN p.reviews r WITH r.status = :status
WHERE p.id = :id"
$q = $em->createQuery($dql);
$q->setParameter('id', $id);
$q->setParameter('status', $status);
$product = $q->getSingleResult();