Symfony 3 Too many parameters - symfony

I'm new to Symfony, and I got an error while running a query :
public function getFilteredArticles($page, $nbPerPage, $data) {
$query = $this->createQueryBuilder('a')
->leftJoin('a.images', 'i')
->addSelect('i')
->leftJoin('a.type_stockage', 't')
->addSelect('t')
->leftJoin('a.famille', 'f')
->addSelect('f');
if ($data['famille'] != '') {
$query->where('f.id = :famille')
->setParameter('famille', $data['famille']);
}
if ($data['rds'] == false) {
$query->where('a.stock_actuel > 0');
}
if ($data['recherche'] != '' && $data['recherche'] != null) {
$query->where('a.ref_article LIKE :recherche')
->setParameter('recherche', '%' . $data['recherche'] . '%');
}
$query->leftJoin('a.sousfamille', 's')
->orderBy('a.ref_article', 'ASC')
->getQuery();
$query->setFirstResult(($page - 1) * $nbPerPage)
->setMaxResults($nbPerPage);
return new Paginator($query, true);
}
This query have conditionnals parameters as you can see, that returns the list of articles I need for a table. But when I run this query to fill my table, I got the error :
An exception has been thrown during the rendering of a template ("Too
many parameters: the query defines 0 parameters and you bound 1").
I don't know why he is expecting 0 parameters. I tried using setParameters instead, but the result is the same.
Does anyone has an idea?

You should use andWhere() methods instead of where().
where() method removes all previous where, but setParameter() does not. That's why he found more parameters than where clauses.
I personally never use where if the condition has no sense to be the first condition, to avoid this kinds of errors.
if ($data['famille'] != '') {
$query->andWhere('f.id = :famille')
->setParameter('famille', $data['famille']);
}
if ($data['rds'] == false) {
$query->andWhere('a.stock_actuel > 0');
}
if ($data['recherche'] != '' && $data['recherche'] != null) {
$query->andWhere('a.ref_article LIKE :recherche')
->setParameter('recherche', '%' . $data['recherche'] . '%');
}
where() php doc
Specifies one or more restrictions to the query result.
Replaces any previously specified restrictions, if any.
andWhere() php doc
Adds one or more restrictions to the query results, forming a logical
conjunction with any previously specified restrictions.

My error, in Symfony 4, using Doctrine 2.6 was
Too many parameters: the query defines 0 parameters and you bound 2
The problem was that I wasn't defining the parameters in andWhere method as
$this->createQueryBuilder('q')
...
->andWhere('q.propertyDate IS NOT NULL') //this also couldn't find anywhere
->andWhere('q.parameterName = :parameterName')
->setParameters(['q.parameterName' => $parameterName, ...2nd parameter])
As I couldn't find any answer to my problem, but was similar to this one, I thought to maybe help someone who is struggling like I was.

also in symfony 5 and 6 you should use andWhere() methods instead of where().
where() method removes all previous where, but setParameter() does not. That's why he found more parameters than where clauses.

Related

Doctrine ORM many-to-many find all by taglist

I'v got simple m2m relation (book -> book_mark <- mark). I want to find item(book) by 1-2-3... x-count of tags(marks). Example: Book1 got these tags: [Mark1, Mark2, Mark3], Book2 got these tags: [Mark1, Mark3, Mark4]. Search list is [Mark1, Mark2]. I want to find only items, which have ALL tags from Search list, i.e. only Book1 in this example.
I have tried many ways and spend much time google it, but didn't find the answer.
Closest that I have is this:
return $this->createQueryBuilder('b')
->select('b, m')
->leftJoin('b.marks_list', 'm')
->andWhere(':marks_list MEMBER OF b.marks_list')
->setParameter('marks_list', $marksList)
->getQuery()->getArrayResult();
But it's looking for books which have at least 1of the parameters, not all of them together
Next, I'v decided that I'm absolutely wrong and start thinking this way:
public function findAllByMarksList(array $marksList)
{
$qb = $this->createQueryBuilder('b')
->select('b, m')
->leftJoin('b.marks_list', 'm');
for ($i = 0; $i<count($marksList); $i++){
$qb->andWhere('m.id in (:mark'.$i.')')
->setParameter('mark'.$i, $marksList[$i]);
}
return $qb->getQuery()->getArrayResult();
}
But here I faced another problem: This code is checking only 1 mark and then always returns an empty set if the number of parameters is more than 1.
Best regards.
So, updated answer... It works (I have relation many to many between reviews and brands) it's the same situation, but for example if you have
Book 1 - mark1, mark2, mark3
Book 2 - mark1, mark2, mark3, mark4
with this code you will also find the book2, because all of it marks are in this list.
If you need to find book which haves only these 3 tags, you additionally need to add checking for count. (Count of tags = count of tagList)
public function test()
{
// just selecting for list for test
$brandsList = $this->_em->createQueryBuilder()
->select('b')
->from('ReviewsAdminBundle:Brands', 'b')
->where('b.id in (:brandIds)')
->setParameter('brandIds', [6,4])
->getQuery()
->getResult();
dump($brandsList);
// query part
$qb = $this->createQueryBuilder('r')
->select('r')
->leftJoin('r.brand', 'brands')
->where('r.published = 1');
foreach ($brandsList as $oneBrand) {
/** #var Brands $oneBrand */
$identifier = $oneBrand->getId();
$qb->andWhere(':brand'.$identifier.' MEMBER OF r.brand')
->setParameter('brand'.$identifier, $identifier);
}
dump($qb->getQuery()->getResult());
die;
}
ps. Additionally you can check doctrine2 queryBuilder must return only result matching with array values (ids): 0/Null and/or One and/or Many id(s) have to return One result (close to our situation)
And, I think there's not better way of accomplishing this. Either you use multiple andWheres to compare id OR use MEMBER OF

From VendorBundle:Entity to FQCN

Is there a way in Symfony to convert a string like
VendorBundle:Foo
into a FQCN like
Vendor\Bundle\Entity\Foo
Extra question
How Doctrine handle this? Because I've seen you can do something like (pseudocode)
->leftJoin( ..., ..., 'WITH', 'alias INSTANCE OF VendorBundle:Entity');
My question is due to
$foo = new \Vendor\Bundle\Entity\Foo();
$foo instanceof 'VendorBundle:Foo'; //false
You can use the php keyword ::class PHP.net
In your case, try something like Foo::class
This should output a string like Vendor\Bundle\Entity\Foo. If you see the comments at the link however, this is not guaranteed if you do not include the correct use statement in your code(use Vendor\Bundle\Entity\Foo) in your controller. If you correctly include that, then you can call Foo::class.
With doctrine functions, you can use the syntax you mentioned VendorBundle:Foo like this:
$manager = $this->getDoctrine()->getManager();
$fooRepository = $manager->getRepository('VendorBundle:Foo');
$fooBar = $fooRepository->find($someId);
For your verification, you have to check
$someStringToCheck = Foo::class;
$foo = new \Vendor\Bundle\Entity\Foo();
$foo instanceof $someStringToCheck //true
Oddly, if you do
$foo instanceof Foo::class
It returns an error
But to use VendorBundle:Foo, then take a look at the AbstractManagerRegistry.php in \Doctrine\Common\Persistence\AbstractManagerRegistry, at the function getManagerForClass($class). You can do something in your code like:
$doctrineStyleString = 'VendorBundle:Foo';
if (strpos($doctrineStyleString, ':') !== false)
{
list($namespaceAlias, $simpleClassName) = explode(':', $doctrineStyleString, 2);
$stringWithPath = $this->getDoctrine()->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
I took the code from that function and tried it out, so stringWithPath should print you Vendor\Bundle\Entity\Foo

Get content of an ArrayCollection

I would like to upgrade my symfony 2 project from 2.3 to 2.7 LTS version. I have a problem in a repository to get result of a query. In 2.3, this query give me something :
public function findProtectedPublications( $steps, $start, $end)
{
$query= $this->getEntityManager()
->createQueryBuilder()
->select('d.pubRefs')
->from('ImpressionDemandBundle:Event', 'h')
->innerJoin('h.demand','d')
->where('d.protectedPublications = :pub')
->setParameter('pub', 1 )
->andWhere('h.date >= :start')
->setParameter('start', $start )
->andWhere('h.date <= :end')
->setParameter('end', $end )
->andWhere('h.stepId in (:steps)')
->setParameter('steps', $steps )
->orderBy('d.id','ASC')
->getQuery();
$results = $query->getResult();
$publications = array();
if ($results && ! empty ($results)){
foreach($results as $result){
$pubs = $result['pubRefs'];
if ($pubs && ! empty($pubs)){
foreach($pubs as $pub){
$publications[] = $pub;
}
}
}
}
return $publications;
}
But this code doesn't work in earlier version because $pubs variable in an ArrayCollection. So I changed the end of my code with this :
$results = $query->getResult();
$publications = array();
if ($results && ! empty ($results)){
foreach($results as $result){
$pubs = $result['pubRefs'];
var_dump($pubs);
if (! $pubs->isEmpty()){
$arrayPubs = $pubs->toArray();
foreach($arrayPubs as $pub){
$publications[] = $pub;
}
}
}
}
return $publications;
In this part, when I dump the $pubs variable, I have :
object(Doctrine\Common\Collections\ArrayCollection)#131 (2) {
["elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
NULL
["_elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
array(1) {
[0]=>
object(Impression\DemandBundle\Entity\Publication)#125 (5) {
["editor":"Impression\DemandBundle\Entity\Publication":private]=>
string(24) "Journal Le Monde 4-10-13"
["coauthors":"Impression\DemandBundle\Entity\Publication":private]=>
string(12) "Machin Machin"
["title":"Impression\DemandBundle\Entity\Publication":private]=>
string(57) "La tragédie de Lampedusa: s"émouvoir, comprendre, agir."
["nbPages":"Impression\DemandBundle\Entity\Publication":private]=>
float(1)
["nbCopies":"Impression\DemandBundle\Entity\Publication":private]=>
float(40)
}
}
}
So it seems that there are elements in this ArrayCollection, but the test $pubs->isEmpty() gives a true result, so I have nothing in $publications array.
Edit: In fact, the problem seems to be due to my data in the database : for an object previous from my upgrade, I have something like this in the database :
O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:54:"Doctrine\Common\Collections\ArrayCollection_elements";a:1:{i:0;O:42:"Impression\DemandBundle\Entity\Publication":5:{s:50:"Impression\DemandBundle\Entity\Publicationeditor";s:5:"BREAL";s:53:"Impression\DemandBundle\Entity\Publicationcoauthors";s:5:"MONOT";s:49:"Impression\DemandBundle\Entity\Publicationtitle";s:18:"USA Canada mexique";s:51:"Impression\DemandBundle\Entity\PublicationnbPages";d:150;s:52:"Impression\DemandBundle\Entity\PublicationnbCopies";d:150;}}}
and this gives the error.
For a object add after my upgrade, I have something like this in the database :
O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollectionelements";a:1:{i:0;O:42:"Impression\DemandBundle\Entity\Publication":5:{s:50:"Impression\DemandBundle\Entity\Publicationeditor";s:8:"dfg dfgd";s:53:"Impression\DemandBundle\Entity\Publicationcoauthors";s:7:"dfg dfg";s:49:"Impression\DemandBundle\Entity\Publicationtitle";s:5:"fdg d";s:51:"Impression\DemandBundle\Entity\PublicationnbPages";d:5;s:52:"Impression\DemandBundle\Entity\PublicationnbCopies";d:3;}}}
and the function findProtectedPublications() works without errors.
The difference between the two versions is ArrayCollection_elements for the first and ArrayCollectionelements for the second.
To correct this data, I tried with
UPDATE demand SET pub_refs = REPLACE (pub_refs, "ArrayCollection_elements', 'ArrayCollectionelements')
but this doesn't work because of special chars. Trying with
UPDATE demand SET pub_refs = REPLACE (pub_refs, "ArrayCollection�_elements', 'ArrayCollection�elements')
doesn't work better. How can I correct this data ?
Doctrine can populate results as an Array instead of an ArrayCollection, simply change the getResult() call to:
$results = $query->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
This would be the most efficient way to complete your task however you could also use ArrayCollection's built-in toArray() method to convert its own data to array format:
$publications = $results->toArray();
As the problem seems to be due to a change in the storage of ArrayCollection in database between 2.3 and 2.7 version of symfony, I created an line command to update these in database.

Drupal filter is not working properly

I'm not sure how to ask it, so if you need anymore additional information, please ask for it!
Situation
I've got a website in three languages. I got a lot of customer cases online each connected to a sector (depending in which sector they belong). Each sector and reference has it's own unique nid.
In my template.php it's stated like this:
if ('sector' == $vars['node']->type) {
$lang = '/'.$vars['language'].'/';
$key_path = $_SERVER['REQUEST_URI'];
$key_path = substr_count($key_path, $lang) ? substr($key_path, strlen($lang)) : $key_path;
if (strpos($key_path, '?')) $key_path = substr_replace($key_path, '', strpos($key_path, '?'));
if (strpos($key_path, 'sectors-references') === 0) {
$view = views_get_view('references');
if (!empty($view)) {
$view->set_arguments((int)$vars['node']->nid);
$vars['content']['suffix'] = $view->render();
}
}
}
And yet, every sector shows me the same references... What do I have to change to get the correct reference under the right sector?
Usually arguments are passed to set_arguments using an array, if you pass a non-array the argument will probably be ignored which is why you're always getting the same result. Try:
$view->set_arguments(array((int)$vars['node']->nid));

GAE more than 3 attributes to filter?

Hie
I am using GAE jdoql and wrote query like:
Query query = pm.newQuery(BloodDonor.class);
query.setFilter(" state == :stateName && district == :distName &&" +
" city == :cityName && bloodGroup == :blood");
#SuppressWarnings("unchecked")
List<BloodDonor> donors = (List<BloodDonor>) query.execute(state.toLowerCase(), district.toLowerCase(),
city.toLowerCase(), bloodGroup.toLowerCase());
This doesnt work as execute method does not support more than 3 parameters. So how to pass more than 3
According to the documentation you can add multiple filters by calling the addFilter method multiple times:
Query query = pm.newQuery("BloodDonor");
query.addFilter("state", Query.FilterOperator.EQUAL, state.toLowerCase());
query.addFilter("district", Query.FilterOperator.EQUAL, city.toLowerCase());
query.addFilter("bloodGroup", Query.FilterOperator.EQUAL, bloodGroup.toLowerCase());
PreparedQuery pq = datastore.prepare(q);
for (Entity result : pq.asIterable()) {
// Do stuff
}
ok figured our myself. The right method is to use query.executeWithArray in this case

Resources