I'm really having a hard time converting this query to Doctrine:
public function get_order($id)
{
$this->db->select('*');
$this->db->from('tbl_orderline');
$this->db->join('tbl_order', 'tbl_order.orderNo = tbl_orderline.orderNo');
$this->db->join('tbl_customer', 'tbl_customer.customerNo = tbl_order.customerNo');
$this->db->join('tbl_product', 'tbl_product.productNo = tbl_orderline.productNo');
$this->db->where('tbl_order.orderNo', $id);
$query = $this->db->get();
return $query->result_array();
}
Could you please help me with this?
Any suggestions? Thanks
// if you're currently in custom Repository class then:
$qb = $this->createQueryBuilder('ol');
// if you're in a controller, then should be:
$qb = $em->getRepository('AppBundle:OrderLine')->createQueryBuilder('ol'); // Or whatever your bundle name is.
// query alias legend:
// ol - order line
// o - order
// c - customer
// p - product
// Your query builder should look something like this:
$qb
->addSelect('o, c, p')
->leftJoin('ol.order', 'o') // this is your relation with [order]
->leftJoin('o.customer', 'c') // this is your relation with [customer] from [order]
->leftJoin('ol.product', 'p') // this is your relation with [product] from [order line]
->where($qb->expr()->eq('ol.id', ':orderLineId')
->setParameter('orderLineId', $id)
->getQuery()
->getOneOrNullResult();
Note:
Since you did not provide any entity mappings, this is completely out of the blue. You are most likely going to change the properties in this query, but at the very least, it should give you the start you need.
Don't hesitate to ask, if you don't understand something.
Ive always found it easier to write in straight dql. Trying to use the querybuilder for complex stuff drives me nuts. This obviously requires you to have the correct relationships mapped in your entities, either annotated or with an orm file.
Obviously its hard to test what Ive put below, so you may need to debug a little.
$query = $this->getEntityManager()->createQuery(
'select orderline, order, customer, product
from BundleName:tlb_orderline orderline
join orderline.orderNo order
join order.customerNo customer
join orderline.productNo product
where order.orderNo = :id');
$query->setParameter('id' => $id);
return $query->getResult();
Related
In PDO / SQL i have a simple query with "bigger than":
DELETE * FROM tablexyz WHERE access > :old
Whats the equivalent in Doctrine 2 ORM?
I have already written a little code:
$criteria = ['access'=>$old];
$dataRepo = $entityManager->getRepository('tablexyz')->findBy($criteria)->delete();
My problem is, i want to use the bigger than operator in Doctrine 2 ORM but i don't want to make a function or class for that. Does somebody know a better or shorter solution for that?
You can use either a query builder og just do a direct DQL (or SQL) query for it.
$qb = $entityManager->createQueryBuilder();
$qb->select('e')
->from('Entityxyz', 'e')
->where('e.access > :old')
->setParameter('old', $old);
$entities = $qb->getQuery()->getResult();
or
$query = 'SELECT e FROM AppBundle\Entity\Entityxyz WHERE e.access > :old';
$entities = $entityManager->createQuery($query)
->setParameter('old', $old)
->getResult();`
I'd suggest you do create a repository method for it though, it's the correct place to have it. Using the query builder inside the repository is also simpler as it knows which entity you're referencing (and can skip calling select and from)
class EntityxyzRepository extends EntityRepository
{
public function getNewerThan($newerThan)
{
$qb = $this->createQueryBuilder('e');
$qb->where('e.access > :newerThan')
->setParameter('newerThan', $newerThan);
return $qb->getQuery()->getResult();
}
}
I have to change something in an existing Symfony2 project, but unfortunately I have never worked with Symfony2 before.
The database contains the following tables:
Location
========
id
....
Deal
========
id
deleted
...
deal_location
=================
deal
location
There is a Many-To-Many relationship between Deal and Location. This is mapped in the Location.orm.yml file like this:
manyToMany:
deals:
cascade: ['all']
targetEntity: Deal
mappedBy: locations
What I want to do is to exclude all deals which where deleted (deleted = 1) when reading the locations from the Database.
As I found out, this can be done in de LocationRepository class. In that class, I found the following function:
public function getFindAllByLatLonQueryBuilder($lat, $lon)
{
$qb = $this->createQueryBuilder('l');
$qb
->where('l.deleted IS NULL OR l.deleted = false')
->orderBy('(((ACOS(SIN((:lat*PI()/180)) *
SIN((l.latitude*PI()/180))+COS((:lat*PI()/180)) *
COS((l.latitude*PI()/180)) * COS(((:lon-l.longitude)*
PI()/180))))*180/PI())*60*1.1515*1.609344)', 'ASC')
->setParameter('lat', $lat)
->setParameter('lon', $lon)
;
return $qb->getQuery()->getResult();
}
I found a similar question and added the following line:
->leftJoin('l.deals', 'deals', 'WITH', 'deals.deleted = 0')
Unfortunately this doesn't work. How can I make this work?
Instead of having two conditions in your where clause I would leave only where('l.deleted IS NOT true AND deals.deleted IS NOT true') and would simply add the leftJoin clause.
Something like this should do the work:
public function getFindAllByLatLonQueryBuilder($lat, $lon)
{
$qb = $this->createQueryBuilder('l')
->leftJoin('l.deal', 'deal', 'WITH', 'deal.deleted IS NOT true') // you can also try 'deal.deleted != true'
->where('l.deleted IS NOT true')
->orderBy('(((ACOS(SIN((:lat*PI()/180)) *
SIN((l.latitude*PI()/180))+COS((:lat*PI()/180)) *
COS((l.latitude*PI()/180)) * COS(((:lon-l.longitude)*
PI()/180))))*180/PI())*60*1.1515*1.609344)', 'ASC')
->setParameter('lat', $lat)
->setParameter('lon', $lon)
;
return $qb->getQuery()->getResult();
}
try
->leftJoin('l.deals', 'deal', 'WITH', 'deal.deleted = 0')
you always have to join the object's name which in your case seems to be deals instead of deal given your yml.
Another thing which makes me wonder is why for location they check on deleted = null or false (see your code) but you check against deleted = 0. Are you sure this is the right check?
leftJoin() not help u, is only needed if u use data from it in query, it not exclude deals, because u in this query get only localization.
I think exclude localization with deleted deals not help to, because in some localization u will have deleted and not deals. It must be in other part of code where u get deals for localizations.
So u must first find where deals are get from db, to make it only take not deleted.
So recently I have been thinking and can't find a solution yet to this problem since my lack of development with doctrine2 and symfony query builder.
I have 2 tables:
Goals: id,user_id,target_value...
Savings: id,goal_id,amount
And I need to make a select from goals (all the informations in my table are from the goals table, except that I need to make a SUM(amount) from the savings table on each goal, so I can show the user how much did he saved for his goal)
This is the MySQL query:
select
admin_goals.created,
admin_goals.description,
admin_goals.goal_date,
admin_goals.value,
admin_goals.budget_categ,
sum(admin_savings.value)
from admin_goals
inner join admin_savings on admin_savings.goal_id=admin_goals.id
where admin_goals.user_id=1
group by admin_goals.id
It returns what I want but I have no idea how to implement it with doctrine or query builder, can you please show me an example in both ways?
I highly appreciate it !
I am going to assume you need this fields only and not your AdminGoals entity. On your AdminGoalsRepository you can do something like this:
public function getGoalsByUser(User $user)
{
$qb = $this->createQueryBuilder('goal');
$qb->select('SUM(savings.value) AS savings_value')
->addSelect('goal.created')
->addSelect('goal.description')
->addSelect('goal.goalDate')
->addSelect('goal.value')
->addSelect('goal.budgetCat') //is this an entity? it will be just an ID
->join('goal.adminSavings', 'savings', Join::WITH))
->where($qb->expr()->eq('goal.user', ':user'))
->groupBy('goal.id')
->setParameter('user', $user);
return $qb->getQuery()->getScalarResult();
}
Keep in mind that the return object will be an array of rows, each row is an associated array with keys like the mappings above.
Edit
After updating the question, I am going to change my suggested function but going to leave the above example if other people would like to see the difference.
First things first, since this is a unidirectional ManyToOne between AdminSavings and AdminGoals, the custom query should be in AdminSavingsRepository (not like above). Also, since you want an aggregated field this will "break" some of your data fetching. Try to stay as much OOP when you are not just rendering templates.
public function getSavingsByUser(User $user)
{
$qb = $this->createQueryBuilder('savings');
//now we can use the expr() function
$qb->select('SUM(savings.value) AS savings_value')
->addSelect('goal.created')
->addSelect('goal.description')
->addSelect('goal.goalDate')
->addSelect('goal.value')
->addSelect('goal.budgetCat') //this will be just an ID
->join('savings.goal', 'goal', Join::WITH))
->where($qb->expr()->eq('goal.user', ':user'))
->groupBy('goal.id')
->setParameter('user', $user);
return $qb->getQuery()->getScalarResult();
}
Bonus
public function FooAction($args)
{
$em = $this->getDoctrine()->getManager();
$user = $this->getUser();
//check if user is User etc depends on your config
...
$savings = $em->getRepository('AcmeBundle:AdminSavings')->getSavingsByUser($user);
foreach($savings as $row) {
$savings = $row['savings_value'];
$goalId = $row['id'];
$goalCreated = $row['created'];
[...]
}
[...]
}
If you use createQuery(), then you can do something like this:
$dqlStr = <<<"DSQL"
select
admin_goals.created,
admin_goals.description,
admin_goals.goal_date,
admin_goals.value,
admin_goals.budget_categ,
sum(admin_savings.value)
from admin_goals
inner join admin_savings on admin_savings.goal_id=admin_goals.id
where admin_goals.user_id=1
group by admin_goals.id
DSQL;
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery($dqlStr);
$query->getResult();
On the other hand, if you would like to use createQueryBuilder(), you can check this link: http://inchoo.net/dev-talk/symfony2-dbal-querybuilder/
I want to get one single value from entity.Can anyone help me here.
Here is my code.Please let me know what is missing here.
$query = $em->createQuery("SELECT e FROM AdminBundle:MailTemplates e WHERE e.keyword = '" .$keywordVal."'");
$query->execute();
$result = $query->getResult();
echo $result ->getId();
Here i want the 'id'.
This is noted in the documentation how you can do this.
So given you're code this will become:
$query = $em->createQuery("SELECT e.id FROM AdminBundle:MailTemplates e WHERE e.keyword = ?1");
$query->setParameter(1, $keywordVal);
$query->execute();
$result = $query->getResult(); // array of MailTemplates ids
Note: I also made use of setParameters instead of setting the value directly in the query.
In your controller:
$this->get('database_connection')->fetchColumn('select id from mail_templates where...');
That's much better for performance and much easier if you don't want to have a deal with query builder and other doctrine orm stuff.
Using the query builder you could do...
$queryBuilder = $em->createQueryBuilder('e');
$queryBuilder
->select('e.yourColumn')
// This will return just this column
// Alternatively you could omit any select to return the whole object
// that you could then use like $object->getYourColumn() if you so chose
->where($queryBuilder->expr()->eq('e.keyword', ':keyword'))
->setParameter('keyword', $keyword)
;
return $queryBuilder
->getQuery()
->getResult();
try this on loading Entities instead of creating own queries
Loading the entity with the Repository.
$rep = $this->getDoctrine()->getManager()->getRepository("Bundlename:Entity");
//find one by keyword -> single entity
$entity = $rep->findOneBy(array('keyword' => $keyword));
//find all by keyword - Array of entities
$result = $rep->findBy(array('keyword' => $keyword));
I'd need to use a "magic finder" findBy method using comparative criteria (not only exact criteria). In other words, I need to do something like this:
$result = $purchases_repository->findBy(array("prize" => ">200"));
so that I'd get all purchases where the prize is above 200.
The class Doctrine\ORM\EntityRepository implements Doctrine\Common\Collections\Selectable API.
The Selectable interface is very flexible and quite new, but it will allow you to handle comparisons and more complex criteria easily on both repositories and single collections of items, regardless if in ORM or ODM or completely separate problems.
This would be a comparison criteria as you just requested as in Doctrine ORM 2.3.2:
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where(\Doctrine\Common\Collections\Criteria::expr()->gt('prize', 200));
$result = $entityRepository->matching($criteria);
The major advantage in this API is that you are implementing some sort of strategy pattern here, and it works with repositories, collections, lazy collections and everywhere the Selectable API is implemented.
This allows you to get rid of dozens of special methods you wrote for your repositories (like findOneBySomethingWithParticularRule), and instead focus on writing your own criteria classes, each representing one of these particular filters.
This is an example using the Expr() Class - I needed this too some days ago and it took me some time to find out what is the exact syntax and way of usage:
/**
* fetches Products that are more expansive than the given price
*
* #param int $price
* #return array
*/
public function findProductsExpensiveThan($price)
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$q = $qb->select(array('p'))
->from('YourProductBundle:Product', 'p')
->where(
$qb->expr()->gt('p.price', $price)
)
->orderBy('p.price', 'DESC')
->getQuery();
return $q->getResult();
}
You have to use either DQL or the QueryBuilder. E.g. in your Purchase-EntityRepository you could do something like this:
$q = $this->createQueryBuilder('p')
->where('p.prize > :purchasePrize')
->setParameter('purchasePrize', 200)
->getQuery();
$q->getResult();
For even more complex scenarios take a look at the Expr() class.
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->gt('id', 'id'))
->setMaxResults(1)
->orderBy(array("id" => $criteria::DESC));
$results = $articlesRepo->matching($criteria);
The Symfony documentation now explicitly shows how to do this:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', '19.99');
$products = $query->getResult();
From http://symfony.com/doc/2.8/book/doctrine.html#querying-for-objects-with-dql
I like to use such static methods:
$result = $purchases_repository->matching(
Criteria::create()->where(
Criteria::expr()->gt('prize', 200)
)
);
Of course, you can push logic when it is 1 condition, but when you have more conditions it is better to divide it into fragments, configure and pass it to the method:
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->where($expr->gt('prize', 200));
$criteria->orderBy(['prize' => Criteria::DESC]);
$result = $purchases_repository->matching($criteria);
Copying the findBy query and modifying it to return your expected result is a good approach.