CakePHP 2.1 Avg function for query - cakephp

I am using cakephp 2.1 and I wanna get average of movie ratings for perticular movie.
Where 'Movie' is a model and it contains 'Language' and 'CriticReview' as models.
The array structure is as follows.
array(
(int) 0 => array(
'Movie' => array(
'id' => '4',
'name' => 'Maattrraan',
'cover_image' => '/movies/4d0d1c41d956a2cb2ab93603d1fdf70c.jpg',
'release' => '2012-10-12',
'runtime' => '',
'budget' => '65 crore',
'box_office' => '',
'language_id' => '2',
'industry_id' => '3'
),
'Language' => array(
'id' => '2',
'name' => 'tamil'
),
'CriticReview' => array(
(int) 0 => array(
'rating' => '4',
'movie_id' => '4'
),
(int) 1 => array(
'rating' => '3',
'movie_id' => '4'
)
)
),
(int) 1 => array(
'Movie' => array(
'id' => '1',
'name' => 'Romeo',
'cover_image' => '/movies/32aa2788fa5e1584d4c627c56214574e.jpg',
'release' => '2012-07-06',
'runtime' => '',
'budget' => '',
'box_office' => '',
'language_id' => '1',
'industry_id' => '1'
),
'Language' => array(
'id' => '1',
'name' => 'kannada'
),
'CriticReview' => array(
(int) 0 => array(
'rating' => '6',
'movie_id' => '1'
),
(int) 1 => array(
'rating' => '3',
'movie_id' => '1'
)
)
));
So I have to avg of critic review. Please help me to find out the solution. The work will be appreciable.

I don't know how your query looks like now, but you can try to add this field:
$this->Movie->find("all", array(
"fields" => array("AVG(CriticReview.rating) AS AverageRating"),
"conditions" => ...
));
The array returned will now contain a sub array within each movie with a key 0 like this
[0] => Array
(
[AverageRating] => AVG_CALCULATED_BY_MYSQL
)
I personally prefer to save calculated data instead of calculate it on fly. Maybe you'd like to read this question: MySQL - Calculating fields on the fly vs storing calculated data

Related

cakephp set:extract array generated by find joins

I have cakephp 2.8 project, I have an array returned by Model->find('all',array('joins')) which is something like this
array(
(int) 0 => array(
'Result' => array(
'id' => '1',
'student_id' => '1',
),
'User' => array(
'fullname' => 'Alam'
)
),
(int) 1 => array(
'Result' => array(
'id' => '2',
'student_id' => '11',
),
'User' => array(
'fullname' => 'Student 1'
)
)
);
I want this array as below
array(
(int) 0 => array(
'id' => '1',
'student_id' => '1',
'fullname' => 'Alam'
),
(int) 1 => array(
'id' => '2',
'student_id' => '11',
'fullname' => 'Student 1'
)
);
I tried Set::extract('/Result/.'); , Set::extract('/Result/User/.'); and other variations but I am not getting desired result.
I know I can do it by foreach loop but I want if it can be done by some builtin php or cakephp function.
I haven't managed to use only one function, but, maybe this will do the trick for you:
$t = Hash::mergeDiff(
Hash::extract($inputArray, '{n}.Result'),
Hash::extract($inputArray, '{n}.User')
);
debug($t);

find by conditions with 'members'

I have 3 model:
Association HasMany Service
Service HasBelongs Association and HasMany Member
Member HasBelongs Service
I want find member by association but I find Service by association.
$associations = $this->Member->Service->Association->find('all',
array(
'fields'=>array('id','libelle')
));
the result debug is:
array(
(int) 0 => array(
'Association' => array(
'id' => '1',
'libelle' => 'الادارة العامة للصحة العسكرية'
),
'Service' => array(
(int) 0 => array(
'id' => '1',
'libelle' => 'Divers',
'association_id' => '1'
),
(int) 1 => array(
'id' => '2',
'association_id' => '1'
),
(int) 2 => array(
'id' => '3',
'libelle' => 'مكتب الضبط BO',
'association_id' => '1'
)
)
),
(int) 1 => array(
'Association' => array(
'id' => '2',
'libelle' => 'أعضاء الديوان والمديرين'
),
'Service' => array()
),
(int) 2 => array(
'Association' => array(
'id' => '3',
'libelle' => 'المستشفات والمراكز والمصحات '
),
'Service' => array()
),
(int) 3 => array(
'Association' => array(
'id' => '4',
'libelle' => 'المستشفى العسكري الاصلي للتعليم '
),
'Service' => array()
)
I want find the member by association example: all member that belong to the Association الادارة العامة للصحة العسكرية ie all members of the services 1, 2, 3
You can use 'contain' to do that.
There are some examples in the book: http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html

CakePHP joing two tables

I have a problem in viewing my data ,I need to return a year,ex(2010,2011,2012,2013) instead of returning the year id , I used contain but It did not work , what is the right way to displaying data ?!
Here is the output array:array(
(int) 0 => array(
'IndicatorDatum' => array(
'id' => '188',
'indicator_id' => '2',
'report_year_id' => '2',
'value' => '144063181',
'comment' => '0',
'reference' => '0'
)
),
(int) 1 => array(
'IndicatorDatum' => array(
'id' => '163',
'indicator_id' => '2',
'report_year_id' => '3',
'value' => '178104575',
'comment' => '0',
'reference' => '0'
)
),
(int) 2 => array(
'IndicatorDatum' => array(
'id' => '137',
'indicator_id' => '2',
'report_year_id' => '4',
'value' => '198637602',
'comment' => '0',
'reference' => '0'
)
),
(int) 3 => array(
'IndicatorDatum' => array(
'id' => '5752',
'indicator_id' => '2',
'report_year_id' => '5',
'value' => '1234',
'comment' => null,
'reference' => null
)
),
(int) 4 => array(
'IndicatorDatum' => array(
'id' => '5694',
'indicator_id' => '2',
'report_year_id' => '6',
'value' => '100',
'comment' => '0',
'reference' => '0'
)
),
(int) 5 => array(
'IndicatorDatum' => array(
'id' => '5271',
'indicator_id' => '2',
'report_year_id' => '6',
'value' => '1',
'comment' => '0',
'reference' => '0'
)
)
)
Model
public $belongsTo = array(
'Indicator' => array(
'className' => 'Indicator',
'foreignKey' => 'indicator_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'ReportYear' => array(
'className' => 'ReportYear',
'foreignKey' => 'report_year_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Organisation' => array(
'className' => 'Organisation',
'foreignKey' => 'organisation_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
);
$this->find('all',array(
'fields' => array('IndicatorDatum.id','IndicatorDatum.indicator_id','IndicatorDatum.report_year_id','IndicatorDatum.value','IndicatorDatum.comment','IndicatorDatum.reference'
),'contain' => array(
'ReportYears'),
'conditions'=>array('IndicatorDatum.indicator_id' =>'2' , 'IndicatorDatum.organisation_id'=>$organisation_id),
'order' => array('IndicatorDatum.report_year_id')
));
You just need to specify the exact fields for each model(including associated models), otherwise only the id is being returned (and it is good, because if it would be all the fields, what if you have some text column in the db with KBs of data - you do not want to retrieve it)
also, please pay attention, that by default(and by cake conventions) model names are singular, so, inside contain it should be ReportYear and not ReportYears.
here is the final query.
$this->find('all', array(
'fields' => array(
'IndicatorDatum.id',
'IndicatorDatum.indicator_id',
'IndicatorDatum.report_year_id',
'IndicatorDatum.value',
'IndicatorDatum.comment',
'IndicatorDatum.reference'
),
'contain' => array(
'ReportYear' => array(
'fields' => array(
'ReportYear.id',
'ReportYear.year' // not sure what you have as a year field name
)
)
),
'conditions' => array(
'IndicatorDatum.indicator_id' => '2',
'IndicatorDatum.organisation_id' => $organisation_id
),
'order' => array(
'IndicatorDatum.report_year_id'
)
)
);

CakePHP: why does format of data retrieved depend on which associated model is called

I have a site with the usual sort of sellers, items and images. The models look like this:
class Seller extends AppModel {
$hasMany = array('Item');
...
}
class Item extends AppModel {
$belongsTo = array('Seller')
$hasMany = array('Image');
...
}
class Image extends AppModel {
$belongsTo = array('Item');
...
}
My problem is that when I retrieve a list of Items, the data comes out in a different format depending on whether I am getting a list of all Items (to display to the public) in the ItemsController, or the details of a Seller and their Items in the SellersController.
Briefly Item->find('all') retrieves an array of
array( 'Item' => array( <item stuff> ),
'Images' => array of array( <image stuff> ) );
whereas the Seller->find('first', ...) retrieves the Items as
array( 'Seller' => array( <seller stuff> ),
'Item' => array of array ( <item stuff>
'Images' => array of array( <image stuff> ) );
In the 2nd case the Images element is nested within the Item part. Having the data formatted so differently makes it harder to re-use View code. Also my Item afterFind() won't work properly has problems when the Images bit isn't where it expects it to be.
QUESTION
Is there a simple way to prevent the 'Images' part being nested within the 'Item' part in the 2nd situation?
I am using Cake 2.4
Formats in More Detail
All items:
// in ItemsController.php
debug($this->Item->find('all'));
produces this:
array(
(int) 0 => array(
'Item' => array(
'id' => '1',
'title' => 'tom item 1',
'seller_id' => '1'
),
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Images' => array(
(int) 0 => array(
'id' => '1',
'item_id' => '1',
'path' => 'tom_1_1'
),
(int) 1 => array(
'id' => '2',
'item_id' => '1',
'path' => 'tom_1_2'
)
)
),
(int) 1 => array(
'Item' => array(
'id' => '2',
'title' => 'tom item 2',
'seller_id' => '1'
),
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Images' => array(
(int) 0 => array(
'id' => '3',
'item_id' => '2',
'path' => 'tom_2_1'
),
(int) 1 => array(
'id' => '4',
'item_id' => '2',
'path' => 'tom_2_2'
)
)
),
...
A single Seller + associated Items:
// In SellersController.php
debug($this->Seller->find('first',
array('conditions' => array('id' => $id), 'recursive' => 2)));
produces:
array(
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Item' => array(
(int) 0 => array(
'id' => '1',
'title' => 'tom item 1',
'seller_id' => '1',
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
// Look! 'Images' is WITHIN 'Item !!!
'Images' => array(
(int) 0 => array(
'id' => '1',
'item_id' => '1',
'path' => 'tom_1_1'
),
(int) 1 => array(
'id' => '2',
'item_id' => '1',
'path' => 'tom_1_2'
)
)
),
(int) 1 => array(
'id' => '2',
'title' => 'tom item 2',
'seller_id' => '1',
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Images' => array(
(int) 0 => array(
'id' => '3',
'item_id' => '2',
'path' => 'tom_2_1'
),
(int) 1 => array(
'id' => '4',
'item_id' => '2',
'path' => 'tom_2_2'
)
)
),
....
This is the expected and correct behavior as Image is not directly associated with Seller, but with Item.
Imagine, how would you determine the proper association when Image would be defined on the same level as Item? That would indicate an association with Seller which doesn't exist.
If you want a different structure, format it in your afterFind callback or wherever it's appropriate. However, I wouldn't recommend trying to work against the CakePHP standards. In case applicable, adapt your view code.
Your question is not clear to me. If just wants to prevent Image to coming in 2nd case, try this
$this->Seller->Item->unbindModel(array(
'hasMany' => array('Image')
));
$result = $this->Seller->find('first',
array('conditions' => array('id' => $id), 'recursive' => 2)));
debug($result);

Accessing the array values in cakephp

I need to access the array elements, from the below array structure.Here i need to access the NewsFeedComment array.I am trying to do this, but it's giving me the error Undefined index: comments
How can i access the elements in the NewsFeedComment array
In Controller:
$this->set('newsfeed',$this->paginate('NewsFeed',$newsfeed));
In view:
<?php foreach ($newsfeeds $newsfeed): ?>
<div class="news_reply_display">
<?php echo $newsfeed['NewsFeedComment'][0]['comments'] ?>
</div>
<?php endforeach; ?>
array(
(int) 0 => array(
'NewsFeed' => array(
'id' => '2',
'title' => 'Best Restaurant',
'group_id' => '1',
'posted_message' => 'message.',
'user_id' => '11',
'created' => '2013-12-03 09:35:02',
'status' => 'A'
),
'Group' => array(
'id' => '1',
'group_name' => 'My group',
'created_user' => '1',
'created_date' => '2013-04-24 15:31:09',
'privacy' => '0',
'membership' => '0',
'description' => 'desc'
),
'NewsFeedComment' => array(
(int) 0 => array(
'id' => '1',
'news_feed_id' => '2',
'comments' => 'comment1',
'status' => 'A'
),
(int) 1 => array(
'id' => '2',
'news_feed_id' => '2',
'comments' => 'comment2',
'status' => 'A'
),
(int) 2 => array(
'id' => '3',
'news_feed_id' => '2',
'comments' => 'comment3',
'status' => 'A'
)
)
),
(int) 1 => array(
'NewsFeed' => array(
'id' => '1',
'title' => 'Test Subject',
'group_id' => '1',
'posted_message' => 'description.',
'user_id' => '1',
'created' => '2013-12-03 08:25:12',
'status' => 'A'
),
'Group' => array(
'id' => '1',
'group_name' => 'secondgroup',
'title' => 'Second Grouups',
'group_slug' => 'secgroup',
'created_user' => '1',
'created_date' => '2013-04-24 15:31:09',
'privacy' => '0',
'membership' => '0',
'description' => 'desc'
),
'NewsFeedComment' => array()
)
)
That index doesn't exist. In that particular case you must use $newsfeed[0]['NewsFeedComment']['comments'].
Now, if you would like to extract all "NewsFeedComent" arrays from $newsfeed then you can use Hash::extract
$newsFeedComments = Hash::extract($users, '{n}.NewsFeedComment');
debug($newsFeedComments);
foreach($newsfeeds as $newsfeed){
foreach($newsfeed['NewsFeedComment'] as $NewsFeedCommentData){
echo $NewsFeedCommentData['comments'];
}
}
Using the above code you will get comments corresponding to each index of array $newsfeeds

Resources