CakePHP same result format as find('list') in Containable - php

I'm looking for a way to have the results of a query that uses the Containable behavior to be formatted the same way as find('list') results are. E.g.:
$this->ModelA->find('all', array(
'contain' => array(
'ModelB' => array(
'ModelC' => array(
// This does NOT work but I need ModelC's fields to be formatted as an associative array where IDs are keys and names are values
'fields' => array('id' => 'name')
)
)
)
));
NOTE: Setting recursive to 1 or 2 instead of using Containable is not an option unless there's no available solution with Containable.

I'm not sure you can get the returned contained data back in the format you want, but you can alter it after finding it. The way Cake actually builds the return from find('list') is using Hash::combine(). So you can alter the returned data using this to make the data look list a find('list') return:-
$data = [
[
'id' => 1,
'name' => 'Foo'
],
[
'id' => 2,
'name' => 'Bar'
]
];
$results = Hash::combine($data, '{n}.id', '{n}.name');
This would return:-
[
1 => 'Foo',
2 => 'Bar'
]
Not sure exactly what your find('all') data looks like as you've not supplied the associations, but guess you can do something like this:-
foreach ($data as &$row) {
$row['ModelB']['ModelC'] = Hash::combine(
$row['ModelB']['ModelC'],
'{n}.id',
'{n}.name'
);
}

$this->ModelA->Behaviors->load('Containable');
$this->ModelA->find('all', array(
'contain' => array( 'ModelB' ,'ModelC'=>array( 'fields' => array('id', 'name'))
)
)
);
Please make sure you have created association of model

Related

Search multidimensional array and returning specific value from that array

I cannot for the life of me figure out how to search through a multidimensional array for a key => value pair, and then either A) Return the array it belongs to or a different specific key => value pair that exists in the same array.
My array is:
$pages = array(
array(
'pageId' => 10,
'title' => 'Welcome',
'theme' => 'basic'
),
array(
'pageId' => 11,
'title' => 'Home',
'theme' => 'basic'
),
array(
'pageId' => 12,
'title' => 'Login',
'theme' => 'basic'
)
);
I've tried
$theme = array_search(10, array_column($search, 'pageId'));
but it keeps returning an int and not the value basic as I am wanting.
I would like either just the value or an array with the key => value pair or the whole array it belongs to.
Try this simplest one, hope this will be helpful. Here we are using array_column
Try this code snippet here
$result=array_column($pages,"theme" ,'pageId');
if(isset($result[$toSearch]))
{
echo $result[$toSearch];
}
You can use array_filter, live demo.
array_filter($array, function($v) use($searchKey, $searchValue) {
return $v[$searchKey] == $searchValue;
});

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.

php multilevel array sort by su-sub-sub array value

I have a multilevel array as below
array(
(int)0=>array(
'User' => array(
'PostType' => array(
'PHP' => array(
'id' => '2',
'type_title' => 'Core Questions',
'type_description' => 'none',
'type_sort_order' => '7'
'Post'=>array(
......
),
),
'ASP' => array(
'id' => '1',
'type_title' => 'Core Questions',
'type_description' => 'none',
'type_sort_order' => '1'
'Post'=>array(
......
),
),
),
)));
I have fetched a user with its post categorized by postType
postType has type_sort_order field
I want to sort sub array PostType by type_sort_order field
so that ASP come before PHP
I tried usort as below
usort($arr,function(){
return ($a[0]['User']['PostType']['post_sort_order'] < $b[0]['User']['PostType']['post_sort_order'])?1:-1;
});
and also many other sort but not getting correct result
array_multisort will work. Solution as follows:
$list = //Your array
$sortOrders = array();
foreach ($list[0]['User']['PostType'] as $postType) {
$sortOrders[] = $postType['type_sort_order'];
}
array_multisort($sortOrders, $list[0]['User']['PostType']);
This will grab all the sort orders in an array ordered the same as your starting array. Using array_multisort on both arrays will sort the first array, and also apply that new order to the second array, giving you the result you're after.
Your looking for http://php.net/manual/en/function.array-multisort.php
Loop though PostType and take all type_sort_order and place in a seperate array. then use that array as an argument for array_multi_sort
it seems you are just trying to sort the sub array PostType so just pass that array

PHP Lithium: Filtering an existent DocumentSet and get first Match

I am retrieving a DocumentSet in Lithium from MongoDB, but I don't want to process the documents all at once. Instead I would like to have a filter, which I just could tell something like this:
$manyDocuments->giveMeTheOneWhere(array('foo' => 'bar'));
I already tried to do it this way, but it didn't work:
$manyDocuments->find(function($singleDocument){
return ($singleDocument->foo == 'bar');
});
Even if I manually return true inside the closure, it always returns an empty DocumentSet.
Just to add clarity: I am not looking for a database-operation, instead I want to get one out of an already existent DocumentSet. Is there a fancy way to achieve this or do I need to iterate through the set using a custom function?
That looks right to me. Is that the exact code you are using?
For example, is the 'bar' value you are using something you are passing in?
I'm on the latest of the master branch of Lithium and wrote this unit test which works for me. I'm not really sure why you're getting an empty DocumentSet.
$docs = new DocumentSet(array('data' => array(
new Document(array('data' => array(
'id' => 1,
'foo' => 'bar'
))),
new Document(array('data' => array(
'id' => 2,
'foo' => 'baz'
))),
new Document(array('data' => array(
'id' => 3,
'foo' => 'bar'
))),
new Document(array('data' => array(
'id' => 4,
'blah' => 'ack'
)))
)));
$filtered = $docs->find(function($doc) {
return $doc->foo === 'bar';
});
$expected = array(
'0' => array('id' => 1, 'foo' => 'bar'),
'2' => array('id' => 3, 'foo' => 'bar')
);
$this->assertIdentical($expected, $filtered->data());
Instead of using find() I just used first() with a closure. This works as expected. Sadly that was the only thing I didn't try before. Excuse me for answering my own question.
Anyway I'd still be interested in a way to get another Document Set.

PHP json_encode won't output proper result

I want to output users via a json object but when I try to output their songs list it only outputs the last one. I want to get this list into an array.
this is my array push while looping through users,
array_push($arrayUsers, array(
'username' => $user['username'],
'id' => $user['_id'],
'favSongs' => array(
'title' =>'song1',
'title' =>'song2'
)
)
);
but this is what I get back (missing song title),
[{"username":"asdfasdfasd","id":{"$id":"4f58d7227edae19c02000000"},"songs":{"title":"song2"}}]
I want it to output the songs like this, but am confused how to get it to do this using PHP:
"songs":[{"title": "song1"}, {"title": "song2"}]
'favSongs' => array(
'title' => 'song1',
'title' => 'song2'
)
PHP will replace the 'title' key with the last one declared.
"songs":[{"title": "song1"}, {"title": "song2"}]
This is an array of objects, so in PHP it needs to be an array of arrays.
'favSongs' => array(
array('title' => 'song1'),
array('title' => 'song2')
)

Categories