What's the BNF of doctrine for? - doctrine

It looks like a big mess,how does it work as reference?
http://www.doctrine-project.org/documentation/manual/1_1/en/dql-doctrine-query-language%3Abnf

I don't think it's used as a reference by any human-being, actually ; but it might be useful if someone want to use some automatic tool that understands BNF ; for instance, some kind of code generator.
The advantage of BNF being that's it's a formal way to describe a language -- much more easier to understand than english, when you are a program.
For reference :
BNF = Backus–Naur Form
Software using BNF
Edit after the comments : Here's a quick example about the DQL / Object stuff :
Let's consider this portion of code, which is using the object-oriented API to write a query, execute it, and get the results (hydrated as arrays -- prints out only the data, this way, when debugging) :
$result = Doctrine_Query::create()
->select('p.id, p.title, u.login')
->from('Ab_Model_Post p')
->innerJoin('p.User u')
->where('p.codeStatus = ?')
->orderBy('p.date desc')
->limit(2)
->execute(array('OK'), Doctrine::HYDRATE_ARRAY);
var_dump($result);
And here's the kind of output you'll get :
array
0 =>
array
'id' => string '7' (length=1)
'title' => string 'Septième post' (length=14)
'User' =>
array
'id' => string '1' (length=1)
'login' => string 'user1' (length=5)
1 =>
array
'id' => string '6' (length=1)
'title' => string 'Sixième post (draft=7)' (length=23)
'User' =>
array
'id' => string '1' (length=1)
'login' => string 'user1' (length=5)
Of course, this is considering the schema and models classes are OK -- and sorry for the example in french, I used a schema/model/database I set up some time ago for a demonstration of Doctrine, which was in french.
Basically, the DB is for a blogging application, and, here, we :
get some data from posts and the user who posted them
for valid posts
the most recents posts
only two posts
Now, here's an equivalent, using what I meant by "DQL" as in "pseudo-SQL language" :
$result = Doctrine_Query::create()
->query(<<<DQL
select p.id, p.title, u.login
from Ab_Model_Post as p,
p.User u
where p.codeStatus = ?
order by p.date desc
limit 2
DQL
, array('OK'), Doctrine::HYDRATE_ARRAY);
var_dump($result);
No object-oriented API here (well, to write the query, I mean) : I only wrote that pseudo-SQL I was thinking about -- which is what the BNF describes, as far as I can tell.
And, of course, the output of the var_dump is exactly the same as the one I got before.
I hope this makes things a bit more clear :-)

It's Backus–Naur Form, a method of describing context free grammars. See this wikipedia article.

Related

Laravel updateOrInsert with 'OR' or 'AND' operator in first arguments?

While it is possible to have multiple arguments for the updateOrInsert in Laravel query builder and what is the operator used by default.
For example in the documentation it is mentioned:
DB::table('users')
->updateOrInsert(
['email' => 'john#example.com', 'name' => 'John'],
['votes' => '2']
);
Does that mean that email && name are checked or does it mean email || name is checked? How can we control it for one or the other if required?
Please forgive me if this is a silly question or if it is not worded as per the correct vocabulary, as I am new to Laravel. I couldn't find this information in the documentation or API.
updateOrInsert() method is used to update an existing record in the database if matching the condition or create if no matching record exists. Its return type is Boolean.
Syntax :
DB::table('blogs')->updateOrInsert(
[Conditions],
[fields with value]
);
In your query :
DB::table('users')->updateOrInsert(
['email' => 'john#example.com', 'name' => 'John'],
['votes' => '2']
);
It will check if email == 'john#example.com' & name == 'john', then it will update votes=2.

Need some help on a somewhat complex LINQ query

I have this query that does what I want which is to return true if any of the materials is comparable in the material groups list.
mgroup.MaterialGroups.Select(x => x.Materials
.Any(m => Convert.ToBoolean(m.Comparable)))
.Any(x => x.Equals(true))
What I would like to add to this query is to also include this one.
mgroup.Materials.Any(m => Convert.ToBoolean(m.Comparable));
How can I combine mgroup and it's materialgroups together in the query so I can select both of their Materials? Thanks.
EDIT - After fighting with LINQ for awhile I broke down and just combined as
mgroup.Materials.Any(m => Convert.ToBoolean(m.Comparable) ||
mgroup.MaterialGroups.Select(x => x.Materials
.Any(c => Convert.ToBoolean(c.Comparable)))
.Any(x => x.Equals(true)))
It works as expected but it's horribly long and it's embedded in an Asp.net MVC view to makes things even worse. If anyone can simplify this that would be amazing.
P.S.- If you are wondering why I added the extra .Any(x => x.Equals(true) at the end it's because without it the query returns an IEnumerable of bools instead of bool.
IEnumerable<Material> allMaterials =
mgroup.Materials.Concat(
mgroup.MaterialGroups.SelectMany(group => group.Materials));
bool result = allMaterials.Any(m => Convert.ToBoolean(m.Comparable));

How can i use Like in cake php

i want the alternative cakephp code for the above query
Select * from book where title like '%java%;
OK, assuming you are using a find() query.
You can specify the conditions array as follows:
"conditions" => array("Book.title like" => "%java%")
or
"conditions" => array("Book.title like '%java%'")
I think both will work
Docu complex find conditions
$this->Post->find('first', array (
"Author.name" => "Bob",
"OR" => array (
"Post.title LIKE" => "%magic%",
"Post.created >" => date('Y-m-d', strtotime("-2 weeks"))
)
));

Yii composite key in relatins with custom params

I want to use composite key in ActiveRecord.
I got two tables.
Quotes and Comments.
Quotes contains pk - id;
Comments pk is composite - module, section, cid
module - module name, where comments come from.
section - section of this module
cid - identificator, in this situaction this is id of quote.
In comments I defined primary key like so.
public function primaryKey()
{
return array('module', 'section', 'cid');
}
Next one, I want to get those records, what related to quotes.
So, in Quotes I declared relation:
'comments' => array(self::HAS_MANY, 'Comment', 'module, section, cid', 'params' => array(
':ypl0' => '"quotes"',
':ypl1' => '"quote"',
':ypl2' => 'id'
)),
The required result is:
SELECT * FROM quotes q
LEFT JOIN comments c ON (c.cid = q.id AND module = "quotes" AND section = "quote")
WHERE c.id IS NULL
SQL is working, relation - not. What I'm doing wrong?
Try the following untested code
'comments' => array(self::HAS_MANY, 'Comment', 'cid','condition'=>'module=:param1 AND section=:param2','params' => array(':param1' => 'quotes',':param2' => 'quote',)),

Where statements are not being appended

I am trying to build a query dynamically. It's initial state is fine. This is the initial where clause that should be present on every query
$qb->add('where', $qb->expr()->andx(
$qb->expr()->eq('s.competitor', $competitor),
$qb->expr()->eq('s.ignored', $ignored),
$qb->expr()->eq('s.id', $params['s_id']),
$qb->expr()->eq('s.id', 'k.targetSite')
), true);
But the app I am building allows users to filter. When that happens, I want to add additional where clauses into my query builder. When this line is executed later in the code, it overwrites the above where statement.
$qb->add('where', $qb->expr()->like($col, $val), true );
From what I have read, the 3rd parameter $append should keep the previous statements, but that's not happening. In Doctrine 1.2, I could just do something like this:
foreach($filter as $col => $val) {
$dql->addWhere($col = ?, array($val));
}
How do I dynamically add where clauses to my QueryBuilder?
Update
Here is a full statement
$where = array('col' => 'k.text', 'val' => 'some word%');
$qb = $this->entityManager->createQueryBuilder()
->select('s, sc')
->from('Dashboard\Entity\Section', 'sc')
->innerJoin('sc.keyword', 'k')
->innerJoin('sc.site', 's')
->leftJoin('k.keywordCategory', 'kc')
->leftJoin('k.keywordSubCategory', 'ksc');
$qb->add('where', $qb->expr()->andx(
$qb->expr()->eq('s.competitor', $competitor),
$qb->expr()->eq('s.ignored', $ignored),
$qb->expr()->eq('s.id', $params['s_id']),
$qb->expr()->eq('s.id', 'k.targetSite')
), true);
if ($where) {
$qb->add('where', $qb->expr()->andx(
$qb->expr()->like($where['col'], $where['val'])
), true);
}
$qb->addGroupBy('k.id');
$qb->addGroupBy('s.id');
$qb->setFirstResult( $params['start'] )
->setMaxResults( $params['limit'] );
$q = $qb->getQuery();
echo $q->getSql();
And the output is
SELECT s0_.id AS id0, k1_.id AS id1, k1_.name AS name2, k2_.id AS id3, k2_.name AS name4, k3_.id AS id5, k3_.text AS text6, k3_.search_vol AS search_vol7, s4_.id AS id8, s4_.sub_domain AS sub_domain9, MIN(s0_.rank) AS sclr10, MAX(s0_.created) AS sclr11
FROM section s0_
INNER JOIN keyword k3_ ON s0_.k_id = k3_.id
INNER JOIN site s4_ ON s0_.s_id = s4_.id
LEFT JOIN keyword_category k1_ ON k3_.k_cat_id = k1_.id
LEFT JOIN keyword_sub_category k2_ ON k3_.k_subcat_id = k2_.id
WHERE k3_.text LIKE 'some word%'
GROUP BY k3_.id, s4_.id LIMIT 25 OFFSET 0
If I don't add in that if ($where) clause, then the first andx where statements are still in place. But when I try to dynamically add them, only the final WHERE statement is added, all others are cleared. I should also add, that I tried it like this as well.
if ($where) {
$qb->add('where', $qb->expr()->like($where['col'], $where['val']), true);
}
I can successfully use
$qb->andWhere( $qb->expr()->like($where['col'], $where['val']) );
But the API docs for Query Builder state the way I am trying to use it should be valid too. Wanted to make sure I was doing it right, or if it was a bug.
You're able to use the ->andWhere() normally (and it will also fixes your issue).
Doctrine 2 QueryBuilder is a rather innovative concept (because it mixes both programmatic and fluent styles), and there are likely bugs associated to it.
One point that you should notice in your code: Instead of play with ->add('where', ...), you should think programmatic. Add more items to andX() object and at the end associate to the ->add('where', ...) (or even better: ->where(...))
Looking at the code, it seems like what you're trying to do won't work, though whether that's documented anywhere or is just a bug is open to question, I think.
In add(), the DQL part you pass in seems only ever to be appended if the part is already stored as an array in the query builder:
$isMultiple = is_array($this->_dqlParts[$dqlPartName]);
...
if ($append && $isMultiple) {
if (is_array($dqlPart)) {
$key = key($dqlPart);
$this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
} else {
$this->_dqlParts[$dqlPartName][] = $dqlPart;
}
} else {
$this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart;
}
And the WHERE clause, unlike most of the other DQL parts, is not initialised to an array:
private $_dqlParts = array(
'select' => array(),
'from' => array(),
'join' => array(),
'set' => array(),
'where' => null,
'groupBy' => array(),
'having' => null,
'orderBy' => array()
);
Now, this looks a bit like it's by design, but Doctrine 2 is fairly new and this bit seems to have been evolving recently. Personally, I'd raise a bug against this behaviour and see what the project people say. If nothing else, you might end up with improved documentation...

Resources