Doctrine 2 - Get all Records - doctrine-orm

Does anyone know is there is a quick way to get all the records in a table using Doctrine with out using the DQL.
Did I miss something or did you need to just write the public function in the class?

If you have an entity class (Doctrine Repository manual):
$records = $em->getRepository("Entities\YourTargetEntity")->findAll();
If you don't have entity class (PDO manual):
$pdo = $em->getCurrentConnection()->getDbh();
$result = $pdo->query("select * from table"); //plain sql query here, it's just PDO
$records = $pdo->fetchAll();

Related

Will Doctrine2 select all fields on all associations (JOINS from a query) to populate the full aggregate object?

I'm researching whether to try Doctrine2 or not. One thing that scares me is the over SELECTing of columns I don't need (ie. consider lots of varchars being selected unnecessarily).
You might ask: but don't you want your full entity object filled? Yes, unless I'm looking for an array hydration. However, many times I don't need the full aggregation filled. Take the association shown below. If I query the Users table with a JOIN on Address, will all the columns from the address table be SELECTed as well (and therefore populated into an address object inside of users object)? Now imagine we have more JOINs. This could get really bad. What if I only want the fields from User populated in just a users only object? I guess I'm a little confused at what Doctrine is doing behind the scenes with associations and query JOINs.
/** #Entity **/
class User
{
// ...
/**
* #ManyToOne(targetEntity="Address")
* #JoinColumn(name="address_id", referencedColumnName="id")
**/
private $address;
}
/** #Entity **/
class Address
{
// ...
}
So does Doctrine2 populate all the fields of all the objects within the aggregate after a query (unless I specifiy partial)?
It depends on your query, but generally it is not implicit.
Using the query builder, you can fetch the associated record like this:
<?php
$qb = $em->createQueryBuilder();
$query = $qb->select(array("u", "a"))
->from("User", "u")
->innerJoin("u.address", "a")
->getQuery();
In the select() statement you specify what to fetch, in this case you get both.
If you only fetch the User records, then when you get the associated record with $user->getAddress(), Doctrine will make the query on the fly and hydrate the Address record for you.
That said, performance wise it is better to select both entities so Doctrine will make only one query and not 1+N queries

Doctrine JOIN syntax

I'm having an issue converting some legacy SQL for the doctrine query builder. I think the problem is in the inner join, but I can't quite work out the parameters the builder is expecting.
This is what I have so far:
$qb = $em->createQueryBuilder();
$qb->select('ob.size', 'ob.colour', 'ob.productId', 'p.title')
->from('m:Option', 'ob')
->innerJoin('m:Product', 'p', 'ON', 'ob.ProductId');
And this is the original query:
query="select size,colour,product_id,title from
products,options_new where
picture = '' and
products.id = options_new.product_id and
product_id like 'UTRW%'
group by product_id";
I normally write joins explicitly, so I'm not certain I'm understanding how the from clause is working here.
At the moment the new query is generating this error:
Expected Doctrine\ORM\Query\Lexer::T_WITH, got 'ON'
Cheers!
Try the query below (drop here your entities, would be more helpful) and for more details about fetching related entities, check the docs: http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#joins
$qb = $em->createQueryBuilder('m');
$qb->select('ob.size', 'ob.colour', 'ob.productId', 'p.title')
->innerJoin('m.product', 'ob');

JPA EclipseLink #ElementCollection join fetch via CriteriaQuery

I have an entity (Book) with an ElementCollection for a List property (tags).
#Entity
#Table(name = "BOOK")
public class Book {
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "BOOK_TAGS", joinColumns = #JoinColumn(name = "BOOK_ID"))
#Column(name = "TAG", length = "4000")
private List<String> tags;
}
For getting a single book, I'm doing entityManager.find and for getting all the books, I'm doing criteria query. This all works. I now want to make the list of tags lazily loaded, which will prevent them from loading when I get all books (which I want) but I still want to load them when I get a particular Book.
My first attempt is to change the entityManager.find to a query. The following works:
select b from Book b left outer join fetch b.tags where b.id = :id
However, I want to do this as a CriteriaQuery as well as add the option for getting tags on the get all books query. Doing the following is not working:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(Book.class);
Root<Book> b = cq.from(Book.class);
b.fetch("tags", JoinType.LEFT);
cq.select(b);
cq.where(cb.equal(b.get("id"),cb.parameter(String.class,"id"));
TypedQuery<Book> q = em.createQuery(cq);
q.setParameter(id);
return q.getSingleResult();
This is failing in that it is not a single result - its looking like N objects where N is the number of tags.
I also tried adding:
q.setHint("eclipselink.join-fetch","b.tags");
and taking out the fetch but that also doesn't work.
I'm getting the columns added to the SQL but its like the processing of those extra columns is messing up the returned object - its either multiples or no object (for hints).
Any ideas how to turn the JOIN FETCH into a proper CriteriaQuery?
Answering my own question - join fetch is not the way to go here as that will mess up result counting - trick is to use batch fetching via QueryHints - and pre-loading the tags as well as a QueryHint.

Can Doctrine2 #OrderBy a calculated field?

I want to sort my model's associated ArrayCollection with a quotient, like this (I know the following code doesn't work):
/**
* #OneToMany (targetEntity="Review", mappedBy="product")
* #OrderBy ({"voted_up / voted_down" = "DESC"})
*/
protected $reviews;
Is something this possible directly in the model definition or do I need to simply use a sort() on the ArrayCollection when requesting the data?
With Doctrine 2.1 you can do that directly in the model definition, but not with #OrderBy. You can define DQL snippets at model level, like stated in the 2.1 Beta release notes:
Named DQL Queries in Metadata: You can add dql queries in the mapping files using #NamedQueries(#NamedQuery(name="foo", query="DQL")) and access them through $em->getRepository()->getNamedQuery().
As such you can create your DQL query with the ORDER BY keywords, something like:
SELECT c.id, c.text, (c.voted_up / c.voted_down) AS sortkey FROM Comment c
ORDER BY sortkey DESC
So, I imagine you add this annotation to the model definition, something like:
/**
* #Entity
* #Table(name="comment")
* #NamedQueries(#NamedQuery(name="sortedComment", query="SELECT c.id, c.text, (c.voted_up / c.voted_down) AS sortkey FROM Comment c ORDER BY sortkey DESC"))
*/
class Comment {
...
}
And then on your code call:
$em->getRepository("Comment")->getNamedQuery("sortedComment");
I didn't test this, but you get the idea.

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();