Using Query Builder in Symfony 2 - php

I am trying to use Query Builder in Symfony2 to get some records from a database. I run the normal query in SQL and it returns the correct results. The query is
SELECT pg.name, pg.description
FROM pm_patentgroups pg
LEFT JOIN pm_portfolios pp ON pp.id = pg.portfolio_id
I want to use the exact query using Doctorine query builder in Symfony2. What I have tried so far is
$repository = $this->getDoctrine()
->getRepository('MunichInnovationGroupBundle:PmPatentgroups');
$query = $repository->createQueryBuilder('pg')
->from('pm_patentgroups', 'pg')
->leftJoin('pg','pm_portfolios','pp','pp.id = pg.portfolio_id')
->getQuery();
$portfolio_groups = $query->getResult();
but its giving me the following error:
Warning: Missing argument 1 for Doctrine\ORM\EntityRepository::createQueryBuilder()
I am new to Symfony2 and Doctorine. Can you please tell me what is going wrong here?
Thanks

You are missing the alias when using createQueryBuilder. Since you have the repository you can drop the from portion and just use
$query = $repository->createQueryBuilder('pg')

Something like:
$qb = $this->getDoctrine()->createQueryBuilder();
$qb->addSelect('pm_patentgroups');
$qb->addSelect('pm_portfolios');
$qb->from('MunichInnovationGroupBundle:PmPatentgroups','pm_patentgroups');
$qb->leftJoin('pm_patentgroups.pm_portfolios','pm_portfolios');
This assumes you have your two entities properly related.
Lots of examples in the D2 manual. Just keep in mind that query builder works with objects, not sql.
And by the way, your error message comes from the fact that the entity repository (as opposed to the entity manager) requires an alias.

Related

Add custom field during select mysql in laravel query

I have this query in laravel 5.2
$obj_custom_stdy_data = QstCustomStudyData::where('student_id', $this->data_user['student_id'])
->select($list_id . ' as list_id ', 'chapter_id', 'subject_id', 'subject_code_id')
->get()
->toArray();
Well I have a fixed value $list_id got from top code. Actually I want to add new field during query selection as list_id. However I got error for such that method.
When I tried in mysql IDE for example:
SELECT (1+2) as total, c.* FROM users
Then the result is no wrong at all.
Is that anyway to write in query builder for laravel instead of raw style?
You can take the use of DB::raw() method of QueryBuilder like this:
->select(DB::raw('(1+2) as total'));
See more about Query Builder's Raw Expressions
Hope this helps!

How to return field names in correct case

I had the need to include in one of my system's DQL queries, a subquery with LIMIT clause. As Doctrine doesn't support it, I changed it to a native query. Yet the native query is returning lower case fields instead of the correct case.
The case is that as this is working code, I had some views depending on this names and it's much harder to change all names.
But I found here http://bit.ly/1Ht1ojH, that this aspect can be configured in Doctrine. So I tried this code:
$conn = $this->getConnection();
$conn->setAttribute(Doctrine_Core::ATTR_FIELD_CASE, CASE_NATURAL);
$res = $conn->query("select MyCasedField from whatever")->fetchAll();
Yet I'm getting the error "Attempted to call method "setAttribute" on class "Doctrine\ORM\EntityManager".
I tried with manager also with same result.
Now I now I can make some code to translate the fields, but I find that the configure solution to be much more clean.
Someone knows why symfony doesn't let me configure the connection ?
Also if there is any way of using LIMIT in a DQL's subquery I would find it better.
There is no LIMIT keyword in DQL. To use this functionality you can call method setMaxResults($limit) on your query object. It is also can be applied to Query Builder.
$query = $this->getEntityManager()
->createQuery('SELECT p FROM Product p')
->setMaxResults($limit);

Doctrine 2 delete with query builder

I have two Entities with relation OneToMany, Project and Services. Now i want to remove all the services by project_id.
First attempt:
$qb = $em->createQueryBuilder();
$qb->delete('Services','s');
$qb->andWhere($qb->expr()->eq('s.project_id', ':id'));
$qb->setParameter(':id',$project->getId());
This attempt fails with the Exception Entity Service does not have property project_id. And it's true, that property does not exists, it's only in database table as foreign key.
Second attempt:
$qb = $em->createQueryBuilder();
$qb->delete('Services','s')->innerJoin('s.project','p');
$qb->andWhere($qb->expr()->eq('p.id', ':id'));
$qb->setParameter(':id',$project->getId());
This one generetate a non valid DQL query too.
Any ideas and examples will be welcome.
You're working with DQL, not SQL, so don't reference the IDs in your condition, reference the object instead.
So your first example would be altered to:
$qb = $em->createQueryBuilder();
$qb->delete('Services', 's');
$qb->where('s.project = :project');
$qb->setParameter('project', $project);
If you really can't get project object and you have to handle only with id you can use this.
Citation from doctrine documentation:
There are two possibilities for bulk deletes with Doctrine. You can either issue a single DQL DELETE query or you can iterate over results removing them one at a time. (Below I paste only first solution)
DQL Query
The by far most efficient way for bulk deletes is to use a DQL DELETE query.
Example that worked in my project
$q = $em->createQuery('delete from AcmeMyTestBundle:TemplateBlock tb where tb.template = '.intval($templateId));
$numDeleted = $q->execute();
In entity TemplateBlock I have property called template which is mapped to template_id in db.
But I agree that highly preferred way of doing it is using objects.

Mongo Doctrine Query Builder Select does not work. Bug?

$dm = $this->get('doctrine.odm.mongodb.document_manager');
$query = $dm->createQueryBuilder('MyBundle:Listing')
->select('title')
->field('coordinates')->geoNear(
(float)$longitude,
(float)$latitude
)->spherical(true);
$classifieds_array = $classifieds->toArray();
$data = array('success'=>true,'classifieds' => $classifieds_array,
'displaymessage' => $classifieds->count(). " Search Results Found");
Even though I am selecting just one field, for my result set, I am getting every thing back in collection along with title. Is this a bug?
NOTE: I commented out the ->field('coordinates')->geoNear((float)$longitude, (float)$latitude)->spherical(true) line and now the select seems to work. This is crazy.
The geoNear command in MongoDB doesn't seem to support filtering result fields, according to the documentation examples. Only a query option is supported to limit matched documents.
In your case, it also looks like mixing up the geoNear() and near() builder methods in Doctrine. Since you're operating on the coordinates field, the appropriate syntax would be near(). geoNear() is a top-level method to tell the builder you wish to use the command, which doesn't require a field name since it uses the one and only geospatial index on the collection.
For usage examples, I would advise looking at the query and builder unit tests in the Doctrine MongoDB library.

Getting Doctrine to use MySQL "FORCE INDEX"

I have a query in Doctrine's DQL that needs to be able to use MySQL's "FORCE INDEX" functionality in order to massively reduce the query time. Below is what the query basically looks like in plain SQL:
SELECT id FROM items FORCE INDEX (best_selling_idx)
WHERE price = ... (etc)
LIMIT 200;
I assume I have to extend some Doctrine component to be able to do this with DQL (or is there a way to inject arbitrary SQL into one of Doctrin's queries?). Anyone have any ideas?
I've found very few helpful Doctrine_RawSql examples online, so here's what I ended up doing to create my query.
$q = new Doctrine_RawSql();
$q->select('{b.id}, {b.description}, {c.description}')
->from('table1 b FORCE INDEX(best_selling_idx) INNER JOIN table2 c ON b.c_id = c.id')
->addComponent('b', 'Table1 b')
->addComponent('c', 'b.Table2 c');
If you don't like native SQL, you can use the following patch. https://gist.github.com/arnaud-lb/2704404
This patch suggests to create only one custom Walker and set it up as follows
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'UseIndexWalker');
$query->setHint(UseIndexWalker::HINT_USE_INDEX, 'some_index_name');
I created a Doctrine SqlWalker extension to apply USE INDEX and FORCE INDEX hints using DQL on top of MySql. Works with both createQuery and createQueryBuilder. You can set different index hints per DQL table aliases.
use Ggergo\SqlIndexHintBundle\SqlIndexWalker;
...
$query = ...;
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, SqlIndexWalker::class);
$query->setHint(SqlIndexWalker::HINT_INDEX, [
'your_dql_table_alias' => 'FORCE INDEX FOR JOIN (your_composite_index) FORCE INDEX FOR ORDER BY (PRIMARY)',
'your_another_dql_table_alias' => 'FORCE INDEX (PRIMARY)',
...
]);
https://github.com/ggergo/SqlIndexHintBundle

Categories