CAKEPHP - Find count of related model (with conditions) - cakephp

I have a model called "User" which has a hasMany relationship to "AdvertisementClicks". I want to find all users that have at least 5 clicks (for example) that were made in the past 5 days. I currently have this:
$params = array(
'conditions' => array(
'User.referrer_id' => NULL,
'User.id !=' => $this->Session->read('MySite.User.id')
),
'contain' => array(
'AdvertisementClick' => array(
'conditions' => array(
'CAST(AdvertisementClick.created AS DATE) >=' => date('Y-m-d', strtotime("-4 days"))
)
)
)
);
$this->User->Behaviors->attach('Containable');
$availableReferrals = $this->User->find('all', $params);
But this will find all the users regardless if they made any clicks or not.
And if possible, limit the find to only return 3 users once it found those 3 users have at least 5 clicks.
Thanks!

I assume that AdvertisementClick belongsTo User
$params = array(
'conditions' => array(
'User.referrer_id' => NULL,
'User.id !=' => $this->Session->read('MySite.User.id'),
'COUNT(AdvertisementClick.id) AS clickcount',
'CAST(AdvertisementClick.created AS DATE) >=' => date('Y-m-d', strtotime("-4 days"))
),
'group' => 'AdvertisementClick.id HAVING clickcount >= 5'
);
$availableReferrals = $this->User->AdvertisementClick->find(
'all',
$params
);

Use group by in query, it will give desired result:
$params = array(
'conditions' => array(
'User.referrer_id' => NULL,
'User.id !=' => $this->Session->read('MySite.User.id'),
'COUNT(AdvertisementClick.id) AS clickcount',
'CAST(AdvertisementClick.created AS DATE) >' => date('Y-m-d', strtotime("-4 days"))
),
'contain' => array(
'AdvertisementClick' => array(
'conditions' => array(
'CAST(AdvertisementClick.created AS DATE) >' => date('Y-m-d', strtotime("-4 days"))
)
)
)
'group'=>'AdvertisementClick.id HAVING clickcount >= 5'
);
$this->User->Behaviors->attach('Containable');
$availableReferrals = $this->User->find('all', $params);

Related

CakePHP is linking models locally, but not on hosted copy?

I have employees who have one employer. In my employees table I have a field called employer_id. A report using this information is working on my local development setup, but not on my web hosting. I can't figure out what might be causing it not to.
When I try to pull up a list of all the employees I get the following error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column
'Employer.last_name' in 'where clause'
SQL Query: SELECT Employee.id, Employee.employer_id,
Employee.first_name, Employee.last_name, Employee.email,
Employee.webinar_id, Employee.questions,
Employee.correct_answers, Employee.required_to_pass,
Employee.status, Employee.role, Employee.sport,
Employee.program, Employee.created, Employee.modified FROM
sportrisk_wp.employees AS Employee WHERE
((Employee.last_name NOT LIKE '') AND (Employer.last_name NOT
LIKE '')) AND contain = '1' ORDER BY Employee.created DESC LIMIT
50
On my local copy when I change debug to 2 I see the following in the SQL log (it's joining the Employer):
SELECT Employee.id, Employee.employer_id,
Employee.first_name, Employee.last_name, Employee.email,
Employee.webinar_id, Employee.questions,
Employee.correct_answers, Employee.required_to_pass,
Employee.status, Employee.role, Employee.sport,
Employee.program, Employee.created, Employee.modified,
Employer.id, Employer.employer_id, Employer.company,
Employer.first_name, Employer.last_name, Employer.phone,
Employer.email, Employer.username, Employer.password,
Employer.usercode, Employer.subscriber, Employer.active,
Employer.admin, Employer.created, Employer.modified,
Employer.status FROM local.employees AS Employee LEFT JOIN
local.users AS Employer ON (Employee.employer_id =
Employer.id) WHERE ((Employee.last_name NOT LIKE '') AND
(Employer.last_name NOT LIKE '')) ORDER BY Employee.created
DESC LIMIT 50
I believe this is all the relevant code.
UsersController
// inside a larger function
// Load Employee Model
$this->loadModel('Employee');
// Base conditions - to hide some old records which do not contain name information.
$conditions = array(
"Employee.last_name NOT LIKE" => '',
"Employer.last_name NOT LIKE" => ''
);
// Find records & paginate
$this->paginate = array(
'limit' => 50,
'conditions' => array(
"AND" => $conditions
),
'order' => array('Employee.created DESC')
);
$employees = $this->paginate('Employee');
?>
Employee Model
<?php
class Employee extends AppModel
{
var $name = 'Employee';
var $recursive = 1;
var $belongsTo = array (
'Employer' => array (
'className' => 'Employer',
'foreignKey' => 'employer_id',
'order' => 'Employee.last_name ASC'
)
);
public $actsAs = array('Containable');
var $validate = array(
'email' => array(
'rule' => 'notBlank'
),
'first_name' => array(
'rule' => 'notBlank'
),
'last_name' => array(
'rule' => 'notBlank'
),
'usercode' => array(
'rule' => 'notBlank'
)
);
}
?>
Employer Model
<?php
class Employer extends AppModel
{
var $name = 'Employer';
var $recursive = -1;
var $hasOne = 'Supervisor';
var $hasMany = 'Employee';
public $useTable = 'users';
public $actsAs = array('Containable');
var $validate = array(
'email' => array(
'rule' => 'notBlank'
),
'password' => array(
'rule' => 'notBlank'
)
);
}
?>
I can't figure out why it isn't linking the Employer model in one environment but is on the other. I've done a straight copy of all the files.
SQL Queries
This is the query I get on the hosted site
SELECT `Employee`.`id`, `Employee`.`employer_id`, `Employee`.`first_name`, `Employee`.`last_name`, `Employee`.`email`, `Employee`.`webinar_id`, `Employee`.`questions`, `Employee`.`correct_answers`, `Employee`.`required_to_pass`, `Employee`.`status`, `Employee`.`role`, `Employee`.`sport`, `Employee`.`program`, `Employee`.`created`, `Employee`.`modified` FROM `sportrisk_wp`.`employees` AS `Employee` WHERE ((`Employee`.`last_name` NOT LIKE '') AND (`Employer`.`last_name` NOT LIKE '')) ORDER BY `Employee`.`created` DESC LIMIT 50
This is what I get on my local site (and what I'm looking for)
SELECT `Employee`.`id`, `Employee`.`employer_id`, `Employee`.`first_name`, `Employee`.`last_name`, `Employee`.`email`, `Employee`.`webinar_id`, `Employee`.`questions`, `Employee`.`correct_answers`, `Employee`.`required_to_pass`, `Employee`.`status`, `Employee`.`role`, `Employee`.`sport`, `Employee`.`program`, `Employee`.`created`, `Employee`.`modified`, `Employer`.`id`, `Employer`.`employer_id`, `Employer`.`company`, `Employer`.`first_name`, `Employer`.`last_name`, `Employer`.`phone`, `Employer`.`email`, `Employer`.`username`, `Employer`.`password`, `Employer`.`usercode`, `Employer`.`subscriber`, `Employer`.`active`, `Employer`.`admin`, `Employer`.`created`, `Employer`.`modified`, `Employer`.`status` FROM `local`.`employees` AS `Employee` LEFT JOIN `local`.`users` AS `Employer` ON (`Employee`.`employer_id` = `Employer`.`id`) WHERE ((`Employee`.`last_name` NOT LIKE '') AND (`Employer`.`last_name` NOT LIKE '')) ORDER BY `Employee`.`created` DESC LIMIT 50
END RESULT
In the end (after a chat with Ved) my paginate array ended up being this, and my report loads.
$this->paginate = array(
'contain' => array('Employer'),
'limit' => 50,
'conditions' => array(
"AND" => $conditions
),
'joins' => array( array( 'alias' => 'Employer', 'table' => 'users', 'type' => 'LEFT', 'conditions' => 'Employer.id = Employee.employer_id' ) ),
'fields' => array('Employee.first_name', 'Employee.last_name', 'Employee.email', 'Employee.webinar_id', 'Employee.questions', 'Employee.correct_answers', 'Employee.required_to_pass', 'Employee.status', 'Employee.role', 'Employee.sport', 'Employee.program', 'Employee.created', 'Employer.id', 'Employer.employer_id', 'Employer.company', 'Employer.first_name', 'Employer.last_name', 'Employer.email', 'Employer.active'),
'order' => array('Employee.created DESC')
);
I think you have forget to load associated data, use contain
// Find records & paginate
$this->paginate = array(
'contain' => array('Employer'),
'fields' => array('Employer.id'), // add more fields
'limit' => 50,
'conditions' => array(
"AND" => $conditions
),
'joins' => array( array( 'alias' => 'Employer', 'table' => 'users', 'type'
=> 'LEFT', 'conditions' => 'Employer.id = Employee.employer_id' ) ),
'order' => array('Employee.created DESC')
);

get data using not ids not working in cakephp

I want to select data for all rows where the below ids dont exist. I thought this would work but there is no error and the below ids still appear in the retrieved records. I am using cakephp 2.5 for this
$ids///
array(
(int) 0 => '14721',
(int) 1 => '14731',
(int) 2 => '14905',
(int) 3 => '15808',
(int) 4 => '15818',
$test=$this->Lessonbak->find('all', array(
'fields'=>array('id'),
'recursive' => -1 ) );
$ids=array();
foreach( $test as $item):
array_push($ids,$item['Lessonbak']['id']);
endforeach;
$lessonstudent2=$this->LessonsStudent2->find('all', array(
'conditions' => array( "NOT" => array( 'LessonsStudent2.lesson_id' => $ids )),
'recursive' => -1 ) );
Instead of selecting all of the Lessonbak ids, pushing them to an array, and using that in your LessonsStudent2 query, you should simply use a subquery:
$dbo = $this->getDataSource();
$subquery = $dbo->buildStatement(
array(
'table' => 'lessonbak',
'alias' => 'Lessonbak',
'recursive' => -1,
'fields' => array(
'Lessonbak.id'
)
),
$this
)
$this->LessonsStudent2->find('all', array(
'conditions' => array(
'NOT' => array(
'LessonsStudent2.lesson_id IN (' . $subquery . ')'
)
)
)

Cakephp find query not working

I am trying to make a query using cakephp model binding. Getting an unexpected result. But whenever I run the query in phpmyadmin it works fine. Getting this error
Column not found: 1054 Unknown column 'Comment.post_id' in 'field list'
Can't figure out what is wrong
PostsController
$posts = $this->Post->find('all', array(
'conditions' => array(
'Post.is_deleted' => 0,
'Post.is_active' => 1,
),
'fields' => array(
'Post.post_id,Post.post_title,Post.post_body,User.username,Post.added_time',
'Product.product_title','COUNT(Comment.post_id) AS total_comment'
),
'GROUP'=>'Post.post_id',
'order' => 'added_time DESC',
));
Post Model
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreign_key' => 'post_id'
),
'Product' => array(
'className' => 'Product',
'foreign_key' => 'post_id'
)
);
public $hasMany = array(
'Comment'=>array(
'className'=>'Comment',
'foreign_key'=>'post_id'
)
);
Comment Model
public $belongsTo = array(
'Post'=>array(
'className'=>'Post',
'foreign_key'=>'post_id'
)
);
My expected query
SELECT posts.`post_title`, users.username,products.product_title, posts.post_body, COUNT(comments.post_id) as total_comments from posts LEFT JOIN comments on comments.post_id = posts.post_id LEFT join users on users.user_id = posts.user_id LEFT JOIN products on products.product_id = posts.product_id WHERE posts.is_active = 1 and posts.is_deleted = 0 GROUP BY posts.post_id
Try by setting the recursive level 1 or 2
$this->Post->find('all', array(
'conditions' => array(
'Post.is_deleted' => 0,
'Post.is_active' => 1,
),
'fields' => array(
'Post.post_id,Post.post_title,Post.post_body,User.username,Post.added_time',
'Product.product_title','COUNT(Comment.post_id) AS total_comment'
),
'GROUP'=>'Post.post_id',
'order' => 'added_time DESC',
'recursive'=>1
));

HABTM and retrieving all Model A that does not has certain Model B

I have 3 tables: users, specialities, specialities_users.
User HABTM Speciality
Speciality HABTM User
SpecialitiesUser belongsTo Speciality,User
I have also model SpecialitiesUser.
When I want to get specialities for given user I can do it through
SpecialitiesUser->find('all' array('conditions' => array('user_id' => $given_user_id));
Now I want to get all specialities that user NOT belongs to. How I can do this in Cake?
The $other_specialities variable in the following code should be what you want:
$the_users_specialities = $this->SpecialitiesUser->find('list', array(
'conditions' => array(
'SpecialitiesUser.user_id' => $given_user_id
),
'fields' => 'SpecialitiesUser.speciality_id'
));
$other_specialities = $this->Speciality->find('all', array(
'conditions' => array(
'NOT' => array(
'Speciality.id' => $the_users_specialities
)
)
));
UPDATE: This is how to do it using a single query:
$db = $this->Speciality->getDataSource();
$sub_query = $db->buildStatement(
array(
'fields' => array('`SpecialitiesUser`.`speciality_id`'),
'table' => $db->fullTableName($this->SpecialitiesUser),
'alias' => 'SpecialitiesUser',
'conditions' => array('`SpecialitiesUser`.`user_id`' => $given_user_id),
),
$this->Speciality
);
$other_specialities = $this->Speciality->find('all', array(
'conditions' => array(
$db->expression('`Speciality`.`id` NOT IN (' . $sub_query . ')')
)
));

Problem with excluding conditions in complex cakephp model

I'm fairly new to cakephp and I'm having a problem with a complicated find function on my models.
I have a number of Groups each containing a number of Users, and each group can make a number of Orders. Each order consists of a number of OrderAmounts which contain an amount and a user_id (relating to a User).
I have a find which finds an Order, and returns all users in the Group relating to that Order and any OrderAmounts corresponding to that user:
$currentOrder = $this->Order->find('first', array(
'conditions' => array(
'Order.group_id' => $this->Session->read("Auth.User.group_id")
),
'contain' => array(
'Group' => array(
'User' => array(
'OrderAmount' => array(
'OrderAmountType'
)
)
)
)
));
What I now want to do is to return a list of all the Users in the Group relating to the Order above who do not have a corresponding OrderAmount.
So far I have this, but I'm not sure where to put the condition to exclude users with OrderAmounts - if I put the conditions in the contains part it simply removes the OrderAmounts from the model, and if I put them in the top level conditions in the find I get an error.
$currentOrderOutstanding = $this->Order->Group->User->find('all', array(
'conditions' => array(
'Group.id' => $this->Session->read("Auth.User.group_id")
),
'fields' => array('User.id'),
'contain' => array(
'OrderAmount',
'Group'
)
));
Take a look at this example from the tutorial:
$this->User->find('all', array(
'contain'=>array(
'Profile',
'Account' => array(
'AccountSummary'
),
'Post' => array(
'PostAttachment' => array(
'fields' => array('id', 'name'),
'PostAttachmentHistory' => array(
'HistoryNotes' => array(
'fields' => array('id', 'note')
)
)
),
'Tag' => array(
'conditions' => array('Tag.name LIKE' => '%happy%')
)
)
)
));
Notice that all the conditions are inside the 'contain' array. Does it help?

Resources