SET a variable into DQL query - php

I want to set a variable into a DQL query on the basis of condition
case when both varibale value are matches the set variable rank.
dql query
$q=$this->em->createQuery("select distinct u.id,u.city,u.country,u.designation FROM Entities\User u JOIN Entities\EventVisitor evt_vstr WITH evt_vstr.user = u.id WHERE (
CASE
WHEN $a =u.designation THEN SET #rank=1
WHEN $b =u.country THEN SET #rank=2
WHEN $c =u.city THEN SET #rank=3
WHEN $d =u.company THEN #rank=4
END) order by #rank")
->setFirstResult($i)
->setMaxResults($max_result);
$results = $q->getResult();
Here rank is the variable i am trying to set
problem im facing
im unable to set variable in dql .
errorlog
PHP Fatal error: Uncaught exception 'Doctrine\\ORM\\Query\\QueryException' with message 'select distinct u.id, u.city,u.country,u.designation FROM Entities\\User u JOIN Entities\\EventVisitor evt_vstr WITH evt_vstr.user = u.id \n\t \t\t\t\t\tWHERE (\n\t\t\t\t\t\t\t\t\tCASE\n\t\t\t\t\t\t\t\t\t\t\t\tWHEN Co-founder =u.designation THEN SET #rank=1\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\tEND ) ' in /home/india/public_html/serve-trade-com/application/libraries/Doctrine/ORM/Query/QueryException.php:39\nStack
But its not working.
How can i do that ?
OR is there any way to do that
Please help

Unfortunately I don't think that's possible in DQL, but you can use just plain SQL with Doctrine. take a look at the createNativeQuery function.
If you want to use it with an Symfony2 Entity, you should also take a look at the Doctrine\ORM\Query\ResultSetMapping class, which is used to create proper Entities out of the result.
Hope this helps.
Btw. In my opinion you shouldn't use PHP variables in your DQL string, but instead work with parameters, you can read about them here.

Related

Getting "Fatal error: Call to a member function fetch_assoc() on a non-object" on SQL query

I have these two tables in my database:
Statements
and Tags
I'm trying to execute this query
SELECT s.id, s.name, s.preview, s.approved FROM Statements s JOIN Tags t ON s.id = t.probID WHERE s.approved = TRUE AND t.tag IN ("Geometry") GROUP BY s.id, s.name, HAVING COUNT(DISTINCT t.tag) = 1,
but getting "Fatal error: Call to a member function fetch_assoc() on a non-object in C:\wamp\www\file.php on line 46", where 46th line is while($row = $res->fetch_assoc()){
Is something wrong with my query?
I suppose you are using MySQLi, correct me if I am wrong.
In the span of time I used it, whenever this kind of problem was presented to me, I had a problem with the query which I was not able to identify before the execution. Given that my query had failed, no SQLStatement object (or whatever its name is) was created. Therefore, no fetch_* method could be called on that!
I believe your problem is a very simple one: you have a trailing comma before your HAVING clause which is messing your query up. I reproduced your SQL structure and query on my PC, and everything worked correctly.
SELECT
s.id, s.name, s.preview, s.approved
FROM
Statements s JOIN Tags t ON s.id = t.probID
WHERE
s.approved = TRUE AND t.tag IN ('Geometry')
GROUP BY s.id, s.name
HAVING COUNT(DISTINCT t.tag) = 1
Try this one out.
Just a note: whenever I have to deal with a true or false in SQL and I am storing it as a *INT UNSIGNED, I feel like using 1 as true and 0 as false never creates any problem, while using TRUE or FALSE sometimes does! This was not the case, anyway :)
If you use var_dump($result); don't use it. Instead of that, put the result in the $result variable. $result = $stmt->get_result();

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

Using Query Builder in Symfony 2

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.

CakePHP: add variables to query in controller

I have a controller action that uses a sql query:
$tag = $this->params['tag'];
$this->set('projects', $this->Project->query('SELECT * FROM projects INNER JOIN projects_tags ON projects.id = projects_tags.project_id INNER JOIN tags on projects_tags.tag_id = tags.id WHERE tags.tag LIKE $tag'));
As you can see at the end I want to use a where clause with the $tag variable but I'm not sure how the syntax would go. As I'm getting the error
Unknown column '$tag' in 'where clause'
Can someone steer me in the right direction?
Ta,
Jonesy
I would strongly advise you to use the Cake ORM instead of raw queries, especially if you're going to plug URL parameters into it. Conditions on HABTM tables can be tricky, but you can build your joins using Cake's ORM syntax as well!
Read the manual, section 3.7.6.9 Joining tables.
Should you want to use Cake's ORM, the following code should provide results equivalent to your raw SQL query:
$this->loadModel('ProjectsTag'); // Load the joining table as pseudo-model
// Define temporary belongsTo relationships between the pseudo-model and the two real models
$this->ProjectsTag->bindModel(array(
'belongsTo' => array('Project','Tag')
));
// Retrieve all the join-table records with matching Tag.tag values
$result_set = $this->ProjectsTag->find('all',array(
'conditions' => array('Tag.tag LIKE' => "%{$tag}%")
));
// Extract the associated Project records from the result-set
$projects = Set::extract('/Project', $result_set);
// Make the set of Project records available to the view
$this->set(compact('projects'));
in php there's a difference between single and double quotes... basically, single quotes dont evaluate the variables... use double quotes instead
And i think that LIKE will need also single quotes.. i'm not really sure
"SELECT * FROM projects INNER JOIN projects_tags ON projects.id = projects_tags.project_id INNER JOIN tags on projects_tags.tag_id = tags.id WHERE tags.tag LIKE '$tag'"
i know.. i know.. people will start talkin' about sql injection.. and the need to scape the caracters... that's another question =)
good luck!
I would at least consider using the cakephp sanitize functions on your tag strings if they are user sourced. See http://book.cakephp.org/view/1183/Data-Sanitization or if using mysql as the db at least consider using http://www.php.net/manual/en/function.mysql-escape-string.php or do something to filter your user input. But the best thing is to make use of the CakePHP orm stuff.
Modify your query as:
$this->set('projects',
$this->Project->query("SELECT * FROM projects
INNER JOIN projects_tags
ON projects.id = projects_tags.project_id
INNER JOIN tags ON projects_tags.tag_id = tags.id
WHERE tags.tag LIKE '" . $tag . "'") //problem was here
);
and it will work.

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