Cakephp 3 query with conditions array build in foreach loop - php

Hello i want to use an array as condition.
For example i have services with a zip as combination
12345 => cleaning,
54321 => cleaning
now i build my array together in a foreach loop
$searcharray = [];
foreach($services as $key => $val){
searcharray[] = array('service' => $val['service'], 'zip' => $val['zip']);
}
My search array lookes like this:
[
(int) 0 => [
'service' => 'cleaning',
'zip' => '12345'
],
(int) 1 => [
'service' => 'cleaning',
'zip' => '54321'
]
]
Then i try to get the data from my request table
$this->loadModel('Requests');
$openrequests = $this->Requests->find('all', array(
'conditions' => array(
'OR' => array(
$searcharray
)
)
));
It didnt work maybe of the keys in the array, because i set after the $searcharray for example [1] and then it works. I dont want to write the condition as string, but how can i solve it?

You have nested the conditions one level too deep.
Your $searcharray is already nested correctly, if you nest it again as in your example, then you're basically creating an OR node with only one child (which in turn has children itself), which is interpreted as basically "nothing", as you need at least two children for an operator to be used. The children in the array nested one level deeper will then be interpreted as AND, as that is the default when no operator is specified.
Long story short, just pass $searcharray as is:
'conditions' => [
'OR' => $searcharray,
]
See also
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions

Related

MongoDB Nested $or query

Example of a Mongo Entry:
array(
'name' => 'blog one',
'blogCategory' => array(
'displayAndLightMeasurement' => '1',
'LEDAndDisplayTestInstrument' => '0'
)
);
A Query like this works fine:
$blogInfoRaw = $collection->find(array('blogCategory' => array('displayAndLightMeasurement' => '1')));
When I try to '$or' query like this:
$blogInfoRaw = $collection->find(array('$or' => array('blogCategory' => array('displayAndLightMeasurement' => '1')),array('blogCategory' => array('LEDAndDisplayTestInstrument' => '1'))));
I get this error:
$or requires nonempty array
What am I doing wrong?
You really meant to use "dot notation" to reference the embedded fields:
$blogInfoRaw = $collection->find(
array(
'$or' => array(
array( 'blogCategory.displayAndLightMeasurement' => '1' ),
array( 'blogCategory.LEDAndDisplayTestInstrument' => '1')
)
)
);
Otherwise the notation you are using implies that the "only" elements present in the embedded level are those that you specify. This is not true since there are multiple keys. So "dot notation" solves this problem by referencing the distinct keys.
PHP array notation does not help here, but the $or needs to be a wrapping "real" array as in [] also.
Issuing a json_encode often helps when comparing to the official MongoDB examples.

CakePHP 2.4.4 How can I sort a multi-dimensional array with Hash::sort by string keys and values?

I don't understand the docs regarding the Hash 'path', so I've had no luck. I'm trying to sort each layer alphabetically:
array(
'music' => array(
'genre' => array(
(int) 0 => 'Dubstep',
(int) 1 => 'Blues',
(int) 2 => 'Classical'
),
'instrument' => array(
(int) 0 => 'Guitar (Electric)',
(int) 1 => 'Bassoon',
(int) 2 => 'Harmonica (Diatonic)'
),
'anotherLot' => array(
I need to sort the first later of arrays by key, then the second later in each by key, and the third by the values, so I imagine the two deeper layers would be done with a nested foreach.
I'm not familiar with CakePHP's Hash class, but here is a plain PHP solution:
ksort($data); // sort main array by keys
foreach ($data as &$outer)
{
ksort($outer); // sort next layer by keys
foreach($outer as &$inner)
{
asort($inner); // sort inner arrays by values
}
}

How is it possible to correctly nest custom fields in a CakePHP find query?

we're often dealing with a code that looks like the following:
return $this->find(
'all', [
'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as count'],
'group' => ['Tag.tag'],
'order' => ['count' => 'DESC']
]);
This query leads us to the following output:
[0] => Array
(
[Tag] => Array
(
[tag] => walls.io
)
[0] => Array
(
[count] => 15
)
)
As you can see, the query returns the results in a "somehow wrong" nesting. The "count" field is unfortunately put into a pseudo [0]-array.
IIRC, CakePHP uses internally a syntax like Tag__field for correctly nesting virtual fields.
When changing the code to the Model__-syntax, the problem stays the same:
return $this->find(
'all', [
'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as Tag__count'],
'group' => ['Tag.tag'],
'order' => ['COUNT(Tag.tag)' => 'DESC']
]);
Output:
[0] => Array
(
[Tag] => Array
(
[tag] => walls.io
)
[0] => Array
(
[Tag__count] => 15
)
)
Workaround 1: array_map
CakePHP pros: Is there a better/more elegant solution than manually mapping the array after the select statement?
$tags = array_map(function($tag) {
$tag['Tag']['count'] = $tag[0]['count'];
unset($tag[0]);
return $tag;
}, $tags);
Workaround 2: virtual field
As described above, the usage of a virtual field might solve this problem:
$this->virtualFields = ['count' => 'COUNT(Tag.Tag)'];
return $this->find(
'all', [
'group' => ['Tag.tag'],
'order' => [$this->getVirtualField('count') => 'DESC']
]);
Unfortunately, with this solution, it's not possible to specify ANY fields at all. only by completely leaving the "fields"-key, the nesting of the array works as expected. when selecting $fields = ['Tag.tag', $this->getVirtualField('count')] the nesting is wrong again.
CakePHP pros: Do you know a method, where the nesting is done right, even if you specify your own fields?
Looking at the CakePHP code, such a method does not exist.
Have a look at the file lib/Cake/Model/Datasource/Database/Mysql.php.
Find the method called: Mysql::resultSet( $results ); (around line 240).
That method maps the result to an array. To determine if a column is part of a table or not it uses PDOStatement::getColumnMeta(). For your "virtual column" that method will return an empty table and so the CakePHP code will put it separately, see the else branch
$this->map[$index++] = array(0, $column['name'], $type);
In order to avoid that else branch you would have to use Virtual fields, but then you run into the other problems that you have noticed.
So you are left with the array_map solution or you could try to overload that Mysql class and add your custom logic at how to identify where a column fits.

PHP / Mongo: how do you update nested data?

I've been playing around with Mongo for about a week now and I still can't work out how to modify nested arrays in Mongo with php.
So here is a sample document...
array (
'_id' => new MongoId("4cb30f560107ae9813000000"),
'email' => 'mo#maurice-campobasso.com',
'firstname' => 'Maurice',
'lastname' => 'Campobasso',
'password' => 'GOD',
'productions' =>
array (
0 =>
array (
'title' => 'a',
'date' => '1286811330.899',
),
1 =>
array (
'title' => 'b',
'date' => '1286811341.183',
),
2 =>
array (
'title' => 'c',
'date' => '1286811350.267',
),
3 =>
array (
'title' => 'd',
'date' => '1286811356.05',
),
),
)
What I wan't to do is delete an array inside the productions array, but I can't work out how. I've been playing with 'update('$pull' => ...etc)' but I haven't been able to make it work.
OK, there are a few ways to do this. In your case, I would do something like
mymongoobject.update( $unset : { "productions.2" : 1 } }
That's basically saying to unset the ".2" element of productions. Some docs here.
Now $pull should also work, but it's a little tougher because "productions" is actually an array of arrays (or objects with sub-objects). So you'd have to match arrays exactly:
mymongoobject.update( $pull : { "productions" : {'title':'d', 'date':'1286811356.05'} }
In the case above, the unset is probably the easiest option (though it will leave a "hole" in the array)
That is actually very easy, unlike traditional sql stuff you just modify the whole data and pass it back.
$cursor = $mongo->yourDB->yourCollection->findOne("_id",4cb30f560107ae9813000000);
//let's remove last item on productions
array_splice($cursor["productions"],2);
//and update the mongo document
echo $mongo->yourDB->yourCollection->update($cursor);
//it echoes 1 if successful
hope it helps.

Need help about array

What do
$categories[$id] = array('name' => $name, 'children' => array());
and
$categories[$parentId]['children'][] = array('id' => $id, 'name' => $name);
mean?
Thanks a lot.
How should i format the output so i can learn the results that was returned?
You can format your code into tables by looping on the array using for or foreach. Read the docs for each if you don't have a grasp on looping.
2.What does
$categories[$id] = array('name' => $name, 'children' => array());
and
$categories[$parentId]['children'][] = array('id' => $id, 'name' => $name);
The first line assigns an associative array to another element of the $categories array. For instance if you wanted the name of the category with ID of 6 it would look like this:
$categories[6]['name']
The second line does something similar, except when you are working with an array in PHP, you can use the [] operator to automatically add another element to the array with the next available index.
What is the uses of .= ?
This is the concatenation assignment operator. The following two statements are equal:
$string1 .= $string2
$string1 = $string1 . $string2
These all have to do with nesting arrays.
first example:
$categories[$id] = array('name' => $name, 'children' => array());
$categories is an array, and you are setting the key id to contain another array, which contains name and another array. you could accomplish something similar with this:
$categories = array(
$id => array(
'name' => $name,
'children' => array()
)
)
The second one is setting the children array from the first example. when you have arrays inside of arrays, you can use multiple indexes. It is then setting an ID and Name in that array. here is a another way to look at example #2:
$categories = array(
$parentID => array(
'children' => array(
'id' = $id,
'name' => $name
)
)
)
note: my two ways of rewriting are functionally identical to what you posted, I'm just hoping this makes it easier to visualize what's going on.

Categories