I'm trying to add a method to a doctrine repository
public function getOpenedImport(Uftts $fattura){
$dql = "SELECT F.importoFattura*C.segnoNumerico - (SELECT SUM(I.importo*C2.segnoNumerico)
FROM MyAppDomain:Incas I
INNER JOIN MyAppDomain:Cjcau AS C2 ON C2.codice = I.causale
WHERE I.annoDocumento = F.annoDocumento AND I.numeroDocumento = F.numeroDocument)
FROM MyAppDomain:Uftts F
INNER JOIN MyAppDomain:Cjcau C ON C.codice = F.causale
WHERE F.annoDocumento = :annoDocumento AND F.numeroDocumento = :numeroDocumento";
$query = $this->getEntityManager()->createQuery($dql);
$query->setParameters(['annoDocumento' => $fattura->getAnnoDocumento(),
'numeroDocumento' => $fattura->getNumeroDocumento()]);
return $query->getSingleScalarResult();
}
This query if executed on my Sql Server 2008 returns the expected result, but using doctrine i get
Error: Expected Literal, got 'SELECT'
I can't find out what's wrong.
$dql variable is not valid DQL. I am not sure how to make it valid also.
You can write plain SQL and run
$this->getEntityManager()->getConnection()->executeQuery($query, $params)
it's a wrapper over PDO, so you will get result like you were performing simple PDO query.
Related
Method in Dao Interface
#RegisterRowMapper(MapMapper.class)
#SqlQuery(
"SELECT Table1.tenantId,Table1.sacTenantId, sacLogId,currentStep,status from Table1 inner join Table2 on Table1.tenantId = Table2.tenantId where <if(tenantId)>Table1.tenantId = :tenantId and<endif> Table2.status = 'FAILED'")
List<Map<String, Object>> getTenantFailedJobDetails(#Define("tenantId") #Bind("tenantId") String tenantId);
Error trace:
"level":"ERROR","categories":[],"msg":"Servlet.service() for servlet
[dispatcherServlet] in context with path [] threw exception [Request
processing failed; nested exception is
org.jdbi.v3.core.statement.UnableToCreateStatementException: Error
rendering SQL template: 'SELECT Table1.tenantId,Table1.sacTenantId,
sacLogId,currentStep,status from Table1 inner join Table2 on
Table1.tenantId = Table2.tenantId where <if(tenantId)>Table1.tenantId
= :tenantId and Table2.status = 'FAILED'' [statement:"null", arguments:{positional:{0:DUMMY-TENANT}, named:{tenantId:DUMMY-TENANT},
finder:[]}]] with root
cause","stacktrace":["org.jdbi.v3.core.statement.UnableToCreateStatementException:
Undefined attribute for token '' [statement:"null",
arguments:{positional:{0:DUMMY-TENANT}, named:{tenantId:DUMMY-TENANT},
finder:[]}]"
What could be wrong with the if condition?
To make if condition in jdbi query work I added annotation #UseStringTemplateEngine of package org.jdbi.v3.stringtemplate4 to the Dao method
If tenandId is not null then where clause will be
Table1.tenantId = :tenantId and Table2.status = 'FAILED'
else where clause will be just
Table2.status = 'FAILED'
One more information to add, for the else part annotation #AllowUnusedBindings package org.jdbi.v3.sqlobject.customizer is required
The syntax you posted is stringtemplate4, so you need to use the stringtemplate 4 engine (which you select with the annotation that you posted). Otherwise you end up with the default engine which does support only very simply substitutions (and not st4 syntax).
I'm using some custom DQL functions to filter rows by some JSONB fields in PostgreSQL. Here's my query function:
private function findTopLevelResources(): array {
return $this->createQueryBuilder('r')
->where("JSON_EXISTS(r.contents, '-1') = FALSE")
->getQuery()
->getResult();
}
Running this code results in DriverException from AbstractPostgreSQLDriver:
An exception occurred while executing 'SELECT r0_.id AS id_0, r0_.marking AS marking_1, r0_.contents AS contents_2, r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.contents?'-1' = false':
SQLSTATE[3F000]: Invalid schema name: 7 ERROR: schema "r0_" does not exist
LINE 1: ... r0_.kind_id AS kind_id_3 FROM resource r0_ WHERE r0_.conten...
^
I tried to execute the raw SQL query manually from PHPStorm and it worked, no errors.
How do I get this to work in Doctrine?
Why doesn't this query work with Doctrine, but does when I test it manually?
Here's JSON_EXISTS: (based on syslogic/doctrine-json-functions)
class JsonExists extends FunctionNode
{
const FUNCTION_NAME = 'JSON_EXISTS';
const OPERATOR = '?';
public $jsonData;
public $jsonPath;
public function getSql(SqlWalker $sqlWalker)
{
$jsonData = $sqlWalker->walkStringPrimary($this->jsonData);
$jsonPath = $this->jsonPath->value;
return $jsonData . self::OPERATOR . "'$jsonPath'";
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->jsonData = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->jsonPath = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
Registered via Symfony's YAML config like this:
doctrine:
orm:
dql:
numeric_functions:
json_exists: Syslogic\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonExists
Versions of stuff:
PHP 7.1.1
doctrine/dbal v2.6.1
doctrine/orm dev-master e3ecec3 (== 2.6.x-dev)
symfony/symfony v3.3.4
The error message is a false clue.
Actual problem is caused by PDO (this is why it works from PHPStorm). When it sees a query like this:
SELECT * FROM foo WHERE contents?'bar'
It treats it like a parametrized query and the question mark ? as a parameter. For some reason it sometimes results in nonsensical error messages. This specific case could be solved by adding a space after the question mark, but it won't work for operators ?| and ?& which can't have a space in the middle.
The solution is to use functions corresponding to operators (this question saved the day). One can find out how they are called using queries like this one:
SELECT oprname, oprcode FROM pg_operator WHERE oprname IN ('?', '?|', '?&')
Here's the part of result related to JSON:
? → jsonb_exists
?| → jsonb_exists_any
?& → jsonb_exists_all
So instead of previous query which causes problems via PDO, one can use this equivalent one:
SELECT * FROM foo WHERE jsonb_exists(contents, 'bar')
I am using Doctrine 2 within ZF2 code and I am trying to write update query.
Code is like this:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->update('Application\Entity\Groups', 'group')
->set('group.state', '?1')
->set('group.modified', '?2')
->where($qb->expr()->eq('group.id', '?3'))
->setParameter(1, \Application\Entity\Groups::STATE_DELETED)
->setParameter(2, $modified)
->setParameter(3, $group_id);
Doctrine2 complains about query. Exact error message is:
(string) [Syntax Error] line 0, col 87: Error: Expected Literal, got 'group'
It seems that keyword group created problems. When I used gr alias instead of group it worked fine.
So, DQL bellow worked:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->update('Application\Entity\Groups', 'gr')
->set('gr.state', ':state')
->set('gr.modified', ':modified')
->where($qb->expr()->eq('gr.id', ':group_id'))
->setParameter('group_id', $group_id)
->setParameter('state', \Application\Entity\Groups::STATE_DELETED)
->setParameter('modified', $modified);
The following would return the a random record with Doctrine:
$name = Doctrine::getTable('nametable')
->createQuery()
->select('name')
->orderBy('RAND()')
->fetchOne();
But I'm running CI2 + Doctrine2, and so it does not work Call to undefined method Doctrine::getTable()
I've tried
$data = $this->doctrine->em->getRepository('ORM\Project\Names')
->orderBy('RAND()')
->fetchOne();
But this does not work either: Uncaught exception 'BadMethodCallException' with message 'Undefined method 'orderBy'. The method name must start with either findBy or findOneBy!'
Perhaps findOneBy is what I want, but it expects an array.
Is there an elegant way to fetch a random record in this setup?
Edit:
This is what I've come up with:
$query = $this->doctrine->em->createQuery("select max(u.id) from ORM\Dynasties2\Femalenames u");
$result = $query->getSingleResult();
$highval = $result[1];
$random_name = rand(1,$highval);
$name = $this->doctrine->em->find('ORM\Dynasties2\Femalenames', $random_name);
$mother_name = $name->getName();
Surely there is a cleaner way??? Apparently there's no such thing as RAND() in CI2/Doctrine2, short of just writing a SQL query.
"orderBy" is not working when you try to access the repository. In this case you have to make a query with "createQuery" or the query builder "createQueryBuilder".
The other way is:
$data = $this->doctrine->em->getRepository('ORM\Project\Names')->findOneBy(array(
'field' => 'ASC or DESC'
));
Here you can test RAND instead ASC or DESC but i think the best way is to make a query.
You can define a function in your repository and make a query that you have all querys in your repo and not in your controller then your first example looks good.
This is what I've come up with:
$query = $this->doctrine->em->createQuery("select max(u.id) from ORM\Dynasties2\Femalenames u");
$result = $query->getSingleResult();
$highval = $result[1];
$random_name = rand(1,$highval);
$name = $this->doctrine->em->find('ORM\Dynasties2\Femalenames', $random_name);
$mother_name = $name->getName();
I assumed there was another way, but cannot discover it.
I'm trying to get all comments for each post in my home page
return
$this->createQueryBuilder('c')
->select('c')
->from('Sdz\BlogBundle\Entity\Commentaire' ,'c')
->leftJoin('a.comments' ,'c')->getQuery()->getResult() ;
but I'm getting this error
[Semantical Error] line 0, col 58 near '.comments c,': Error:
Identification Variable a used in join path expression but was not defined before.
PS : The mapping is correct because I can see the page article with its comments.
In case this is still giving you problems, here is your query using the syntax found in the examples in the Doctrine 2.1 documentation.
I'm assuming your query resides in a custom repository method, and that 'a' is an abbreviation for 'Article'.
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb->select(array('a', 'c'))
->from('Sdz\BlogBundle\Entity\Article', 'a')
->leftJoin('a.comments', 'c');
$query = $qb->getQuery();
$results = $query->getResult();
return $results;