A hash::combine array - cakephp

I have this array from a sql query :
[0] => Array
(
[T1] => Array
(
[First] => A
[Second] => Apples
[LastChild] => F
)
[0] => Array
(
[LastChildNb] => 23
)
)
I would like to have this result :
[0] => Array
(
[0] => Array
(
[First] => A
[Second] => Apples
[LastChild] => F
[LastChildNb] => 23
)
)
How do I do this ? I think I should use "hash::combine", but what would the code be ?

You could do something like this, with $arr being your array above:
$arr = array_reduce($arr, function(&$arr, $v) {
return array_merge($arr, (array) $v);
}, array());

You can do
array_merge($arr[0]['T1'], $arr[0][0])
Where $arr is defined as follows:
$arr = [0 => Array
(
'T1' => Array
(
'First' => 'A',
'Second' => 'Apples',
'LastChild' => 'F'
),
0 => Array
(
'LastChildNb' => 23
)
)];
For multiple records in $arr, you can simply cycle over all records and do this merge manually.
However, assuming you're getting the array as a result of a find() method, I suggest you consider using T1__LastChildNb as an alias within the 'fields' of your condition. Simply said, if you have a find like following:
$this->T1->find('all', ['fields' => 'T1.*, (SOME SUBQUERY) AS LastChildNb']);
then modifying it to be
$this->T1->find('all', ['fields' => 'T1.*, (SOME SUBQUERY) AS T1__LastChildNb']);
might be what you're looking for since it will return desired array directly (tested on 2.6).
Let me know if you're interested in more information.

Related

Combine/merge results from two queries from different databases

I am trying to produce a web report using PHP that takes a query from a SQL Server database for the main query, and another query from a PostgreSQL database.
What is the best way to merge the results? Currently I am outputting the results as arrays.
The two arrays are made up like so:
Array1
(
[0] => Array
(
[site_name] => TESTSITE
[status] => 1
)
)
Array2
(
[0] => Array
(
[site_name] => TESTSITE
[booking_id] => 2156
[jobresults_key] => 1239
[result] => 4
)
)
The common items are [site_name] in both arrays, and I want to display the [status] from array1 if there is nothing for the matching [site_name] in array2, if there is a matching [site_name] in array2 then it should display [result].
As long as the arrays are short and array1 is always larger, this should work fine.
$array1 = array(
array(
'site_name' => 'TESTSITE',
'status' => 1
),
array(
'site_name' => 'TESTSITE-2',
'status' => 1
)
);
$array2 = array(
array(
'site_name' => 'TESTSITE',
'booking_id' => 2156,
'jobresults_key' => 1239,
'result' => 4
)
);
foreach($array1 as &$item1){
foreach($array2 as $item2){
if( $item1['site_name'] === $item2['site_name'] ){
$item1 = array_replace($item1, $item2);
}
}
}
print_r($array1);

How to use Hash on the query builder results in CakePHP 3.x?

This is my code
$all = $this->find()
->select(['ProductCircles.id', 'ProductCircles.type', 'ProductCircles.name'])
->order(['ProductCircles.type'])
->all()
->toArray();
Log::write('error', $all);
$all = Hash::combine($all, '{n}.ProductCircles.id', '{n}.ProductCircles.name', '{n}.ProductCircles.type');
The $all is an array of ProductCircle entities.
However, the Hash combine is unable to act on the data as I expected.
Please advise.
$all was expected to be an array of ProductCircle entities:
2015-03-15 08:04:36 Error: Array
(
[0] => App\Model\Entity\ProductCircle Object
(
[_accessible:protected] => Array
(
[name] => 1
[type] => 1
[product_count] => 1
[products_in_circles] => 1
)
[_properties:protected] => Array
(
[id] => 27
[type] => MATERIAL
[name] => Wood
)
[_original:protected] => Array
(
)
[_hidden:protected] => Array
(
)
[_virtual:protected] => Array
(
)
[_className:protected] => App\Model\Entity\ProductCircle
[_dirty:protected] => Array
(
)
[_new:protected] =>
[_errors:protected] => Array
(
)
[_registryAlias:protected] => ProductCircles
)
Which is what I expected.
What I want to do with the Hash::combine is to get an array of arrays like this:
$result:
[
[MATERIAL] => [
[27] => [
Wood
]
]
Don't use Hash, but the collection methods that are built into the query object:
$combined = $this->find()
->select(['ProductCircles.id', 'ProductCircles.type', 'ProductCircles.name'])
->order(['ProductCircles.type'])
->combine('id', 'name', 'type')
->toArray();
To expand on José's answer (and using the extract() because that's the one I needed):
$query = $this->MyTable->find('all', [
'contain' => [
'ProductCircles',
],
// ...
]);
return $query->all()->extract('ProductCircles.name');
More info: book.cakephp.org/3/en/core-libraries/collections.html#Cake\Collection\Collection::extract

Extracting values from arrays in custom fields

I'm trying to come up with a single array of all values in specific custom fields. The values themselves are also arrays. I've tried all sorts of array functions but haven't come across the right one or the right combination. Here is my code thus far:
$args = array(
'post_type' => 'match_report',
'post_status' => 'publish',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'report_home-scorers'
),
array(
'key' => 'report_away-scorers'
)
)
);
$reportscore = new WP_Query($args);
$scorersResults = array();
if ( $reportscore->have_posts() ) {
while ( $reportscore->have_posts() ) {
$reportscore->the_post();
$homescorers = get_post_meta($post->ID,'report_home-scorers',false);
$awayscorers = get_post_meta($post->ID,'report_away-scorers',false);
foreach ($homescorers as $homescorer){
array_push($scorersResults, $homescorer);
}
foreach ($awayscorers as $awayscorer){
array_push($scorersResults, $awayscorer);
}
?>
<?php } wp_reset_postdata(); //endif
}//endwhile
$scorerResults = remove_empty($scorersResults);
function remove_empty($array) {
return array_filter($array, '_remove_empty_internal');
}
function _remove_empty_internal($value) {
return !empty($value) || $value === 0;
}
Here what I get if I print_r($scorerResults); :
Array
(
[1] => Array
(
[0] => 1
[1] => 63
)
[2] => Array
(
[0] => 263
[1] => 195
)
[3] => Array
(
[0] =>
)
[4] => Array
(
[0] =>
)
)
I just want the values in the internal arrays in an array.
Assuming you want the $scoreResults array to end up as array(1,63,263,195) you could use the array_reduce function like this:
function gatherScores($lhs, $rhs) {
foreach ($rhs as $key => $value)
if ($value)
$lhs[] = $value;
return $lhs;
}
$scorerResults = array_reduce($scorerResults, "gatherScores", array());
I'm not sure what the blank values are in your third and fourth arrays and how they should be handled, so you may need to change the if ($value) condition to check for something different. As it stands it'll obviously also filter out zero scores.

Convert 3 dimension to 2 dimension

I got a query result like this : -
Array(
[0] => Array
(
[0] => Array
(
[id] => 1
[name] => Japan
)
)
[1] => Array
(
[0] => Array
(
[id] => 2
[name] => Nepal
)
)
}
How can I convert it to
Array
(
[0] => Japan
[1] => Nepal
)
The query used to get first array is 'select id , name from country;'
Please help me.
foreach ($element as $array) {
$element = $element[0]["name"];
}
Or,
function extractName($element) {
return $element[0]["name"];
}
$newArray = array_map("extractName", $array);
Extract!
$newArray = Set::extract($oldArray, '{n}.0.name');
More here.

Getting CakePHP's searchable behavior results to contain deeper associations

I am trying to use CakePHP 1.3.5's searchable behavior with containable behavior to return search results for a specified model and an associated model (Article belongsTo User).
Ignoring the searchable behavior for a moment, the following call to find():
$this->Article->find('all', array(
'conditions' => array('Article.is_published' => 1),
'fields' => array('Article.id'),
'contain' => array('User.name')
));
Executes this SQL query:
SELECT `Article`.`id`, `User`.`name`, `User`.`id` FROM `articles` AS `Article` LEFT JOIN `users` AS `User` ON (`Article`.`user_id` = `User`.`id`) WHERE `Article`.`is_published` = 1
And returns the following array:
Array (
[0] => Array (
[Article] => Array (
[id] => 10
)
[User] => Array (
[name] => Author Name
[id] => 7
)
)
...
)
Which is exactly what's expected. However, the following call to search():
$this->Article->search($query, array(
'conditions' => array('Article.is_published' => 1),
'fields' => array('Article.id'),
'contain' => array('Article' => array('User.name'))
));
Executes this SQL query:
SELECT `Article`.`id` FROM `search_index` AS `SearchIndex` LEFT JOIN `articles` AS `Article` ON (`SearchIndex`.`model` = 'Article' AND `SearchIndex`.`association_key` = `Article`.`id`) WHERE `Article`.`is_published` = 1 AND MATCH(`SearchIndex`.`data`) AGAINST('search term' IN BOOLEAN MODE) AND `Article`.`id` IS NOT NULL
And returns this array:
Array (
[0] => Array (
[Article] => Array (
[id] => 9
)
)
...
)
Looking at the search() method, it is returning $this->SearchIndex->find('all', $findOptions);. $findOptions contains the following:
Array (
[conditions] => Array (
[Article.is_published] => 1
[0] => MATCH(SearchIndex.data) AGAINST('search term' IN BOOLEAN MODE)
)
[fields] => Array (
[0] => Article.id
)
[contain] => Array (
[Article] => Array (
[0] => User.name
)
)
)
The association isn't getting lost along the way, because inside SearchableBehavior, $this->SearchIndex->Article->belongsTo['User'] is present and intact immediately before and after the call to find() inside the search() method.
The call to search() returns the exact same thing for all of the following values of 'contain':
array('Article' => array('User.name'))
array('Article' => array('User'))
array('Article' => array('User' => array()))
array('Article' => array('User' => array('fields' => array('User.name'))))
array('Article' => array('User' => array('fields' => array('name'))))
Am I doing something wrong? I think I'm using the same format as is instructed in the CakePHP documentation, and I haven't found anything online that suggests that you have to do something special to get search results with associated data.
I know that I could easily achieve the result that I want by just looking up the Users with additional calls to find(), but I'd like to get containable behavior to work like it's supposed to and cut down on unnecessary extra database queries.
When using containable, set the recursive option to "true"
$this->Model->Behaviors->attach("Containable",array("recursive"=>true));

Resources