Related
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')
);
I am having a strange behavior which I do not understand with my cakephp 2.
In my Model 'Study' I have a has many relation:
class Study extends AppModel {
public $hasOne = array(
'SubjectFilter' => array(
'className' => 'Subject_filter',
'dependent' => true
)
);
public $hasMany = array(
'ExecutedStudyTable' => array(
'className' => 'ExecutedStudyTable',
'foreignKey' =>'study_id',
'dependent' => true,
),
);
The ExecutedtStudyTable Model looks like this:
class ExecutedStudyTable extends AppModel {
public $belongsTo= array(
'Study' => array(
'className' => 'Study',
'foreignKey' => 'study_id'
),
'User' => array(
'className' => 'User',
'foreignKey' => false,
'conditions' => array('ExecutedStudyTable.user_id = User.id')
)
);
}
When retrieving data everything looks good until I try to do this:
$studies = $this -> Study -> find('all',array(
'conditions' => array(
'Study.user_id' => $cId,
'OR'=>array(
array('Study.state'=>'active'),
array('Study.state'=>'rehearsal')
),
'SubjectFilter.studyCode'=>null,
'ExecutedStudyTable.user_id'=>$user
)
));
I get this error: Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'ExecutedStudyTable.user_id' in 'where clause'
Cakephp builds this query like this:
SELECT `Study`.`id`, `Study`.`user_id`, `Study`.`created`, `Study`.`modified`, `Study`.`started`, `Study`.`completed`, `Study`.`title`, `Study`.`description`, `Study`.`numberParticipants`, `Study`.`state`, `User`.`id`, `User`.`username`, `User`.`password`, `User`.`role`, `User`.`firstName`, `User`.`familyName`, `User`.`email`, `User`.`addressStreet`, `User`.`addressCity`, `User`.`addressZip`, `User`.`phone1`, `User`.`phone2`, `User`.`created`, `User`.`modified`, `User`.`passwordResetCode`, `User`.`passwordResetDate`, `User`.`sendUsernameDate`, `SubjectFilter`.`id`, `SubjectFilter`.`study_id`, `SubjectFilter`.`m`, `SubjectFilter`.`f`, `SubjectFilter`.`age18_24`, `SubjectFilter`.`age25_34`, `SubjectFilter`.`age35_44`, `SubjectFilter`.`age45_54`, `SubjectFilter`.`age55plus`, `SubjectFilter`.`studyCode` FROM `eyevido`.`studies` AS `Study` LEFT JOIN `eyevido`.`users` AS `User` ON (`Study`.`user_id` = `User`.`id`) LEFT JOIN `eyevido`.`subject_filters` AS `SubjectFilter` ON (`SubjectFilter`.`study_id` = `Study`.`id`) WHERE `Study`.`user_id` = 1402402538 AND ((`Study`.`state` = 'active') OR (`Study`.`state` = 'rehearsal')) AND `SubjectFilter`.`studyCode` IS NULL AND `ExecutedStudyTable`.`user_id` = 1130451831
The ExecutedStudyTable is not joined like the SubjectFilter and no alias is defined for the table. Why is this working correctly on the hasOne relation and not on the hasMany? Where do I make the mistake?
I appreciate your replies
If you want to filter a model by associated model's field, one way is by Joining tables.
Note: Mention proper table name for model ExecutedStudyTable. Also mention the join condition between two tables.
$studies = $this->Study->find('all',array(
'fields' => array('Study.*'),
'joins' => array(
array('table' => 'executed_study_table', // Table name
'alias' => 'ExecutedStudyTable',
'type' => 'INNER',
'conditions' => array(
'ExecutedStudyTable.<field name> = Study.<field>', // Mention join condition here
)
)
),
'conditions' => array(
'Study.user_id' => $cId,
'OR'=>array(
array('Study.state'=>'active'),
array('Study.state'=>'rehearsal')
),
'SubjectFilter.studyCode' => null,
'ExecutedStudyTable.user_id' => $user
),
'recursive' => -1
));
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 . ')')
)
));
I am in the FilesController and I'm trying to get a file based on the condition that its order belongs to the current user.
FilesController
// Check the file exists and that it belongs to the user
$this->File->find('first', array(
'conditions' => array(
'File.id' => $id,
'Order.Customer.id' => $this->Auth->user('id')
),
'recursive' => 2
));
Cake SQL Error
Unknown column 'Order.Customer.id' in 'where clause'
I'm trying to get the SQL to left join orders onto files and then left join customers onto orders, but I can't figure out how to join the customers table, although I'm sure I've done this before. I've tried everything I can think of with the conditions, and using contains.
Here's my model relationships:
Customer Model
class Customer extends AppModel {
public $hasMany = array('Order');
}
Order Model
class Order extends AppModel {
public $belongsTo = array('Customer');
public $hasMany = array('File');
}
File Model
class File extends AppModel {
public $belongsTo = array('Order');
}
Try joining the tables using the 'joins' parameter. Sometimes 'contains' doesn't work and you need to fall back on this.
$this->File->find('first', array(
'conditions' => array(
'File.id' => $id,
'Order.Customer_id' => $this->Auth->user('id')
),
'joins' => array(
array(
'table' => 'orders',
'alias' => 'Order',
'type' => 'LEFT',
'conditions' => array('File.orders_id = Order.id')
),
array(
'table' => 'customers',
'alias' => 'Customer',
'type' => 'LEFT',
'conditions' => array('Customer.orders_id = Order.id')
)
)
));
You may want to use Containable (http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html) as it is the easiest solution. You can not use Order.Customer.id as Cake does not nest conditions like that. Manual joins would also work.
$this->loadModel('Customer');
$customer = $this->Customer->findById($this->Auth->user('id'), array(
'conditions' => array(
'File.id' => $id
),
'recursive' => 2
));
Orders will be accessible as:
pr($customer['Order']);
File will be accessible as:
pr($customer['File']);
I realised there is no need to actually join the customers table in this instance, because the orders table already has the customer_id.
$this->File->find('first', array(
'conditions' => array(
'File.id' => $id,
'Order.customer_id' => $this->Auth->user('id')
)
));
I've been working with cakephp paginations options for 2 days. I need to make a INNER Joins to list a few fields, but I have to deal with search to filter results.
This is portion of code in which I deal with search options by $this->passedArgs
function crediti() {
if(isset($this->passedArgs['Search.cognome'])) {
debug($this->passedArgs);
$this->paginate['conditions'][]['Member.cognome LIKE'] = str_replace('*','%',$this->passedArgs['Search.cognome']);
}
if(isset($this->passedArgs['Search.nome'])) {
$this->paginate['conditions'][]['Member.nome LIKE'] = str_replace('*','%',$this->passedArgs['Search.nome']);
}
and after
$this->paginate = array(
'joins' => array(array('table'=> 'reservations',
'type' => 'INNER',
'alias' => 'Reservation',
'conditions' => array('Reservation.member_id = Member.id','Member.totcrediti > 0' ))),
'limit' => 10);
$this->Member->recursive = -1;
$this->paginate['conditions'][]['Reservation.pagamento_verificato'] = 'SI';
$this->paginate['fields'] = array('DISTINCT Member.id','Member.nome','Member.cognome','Member.totcrediti');
$members = $this->paginate('Member');
$this->set(compact('members'));
INNER JOIN works good, but $this->paginations ignore every $this->paginate['conditions'][] by $this->passedArgs and I cannot have idea how I can work it out.
No query in debug, just the original INNER JOIN.
Can someone helps me ?
Thank you very much
Update:
No luck about it.
I've been dealing with this part of code for many hours.
If I use
if(isset($this->passedArgs['Search.cognome'])) {
$this->paginate['conditions'][]['Member.cognome LIKE'] = str_replace('*','%',$this->passedArgs['Search.cognome']);
}
$this->paginate['conditions'][]['Member.sospeso'] = 'SI';
$this->Member->recursive = 0;
$this->paginate['fields'] = array(
'Member.id','Member.nome','Member.cognome','Member.codice_fiscale','Member.sesso','Member.region_id',
'Member.district_id','Member.city_id','Member.date','Member.sospeso','Region.name','District.name','City.name');
$sospesi = $this->paginate('Member');
everything goes well, and from debug I receive the first condition and the conditions from $this->paginate['conditions'][]['Member.cognome LIKE'], as you can see
array $this->passedArgs
Array
(
[Search.cognome] => aiello
)
Array $this->paginate['conditions'][]
(
[0] => Array
(
[Member.cognome LIKE] => aiello
)
[1] => Array
(
[Member.sospeso] => NO
)
But, if I write the joins with paginate , $this->paginate['conditions'][] will ignore all the stuff, and give me from debug, just $this->paginate['conditions'][]['Reservation.pagamento_verificato'] = 'SI';
Another bit of information.
If I put all the stuff dealing with $this->paginate['conditions'][]['Reservation.pagamento_verificato'] = 'SI';
before the $this->paginate JOIN, nothing will be in $this->paginate['conditions'][].
This is an old question, so I'll just review how to do a JOIN in a paginate for others who got here from Google like I did. Here's the sample code from the Widget's Controller, joining a Widget.user_id FK to a User.id column, only showing the current user (in conditions):
// Limit widgets shown to only those owned by the user.
$this->paginate = array(
'conditions' => array('User.id' => $this->Auth->user('id')),
'joins' => array(
array(
'alias' => 'User',
'table' => 'users',
'type' => 'INNER',
'conditions' => '`User`.`id` = `Widget`.`user_id`'
)
),
'limit' => 20,
'order' => array(
'created' => 'desc'
)
);
$this->set( 'widgets', $this->paginate( $this->Widget ) );
This makes a query similar to:
SELECT widgets.* FROM widgets
INNER JOIN users ON widgets.user_id = users.id
WHERE users.id = {current user id}
And still paginates.
I'm not sure if you need those [] - try just doing this:
$this->paginate['conditions']['Reservation.pagamento_verificato'] = 'SI';
I use the conditions when I call paginate method.
$this->paginate($conditions)
This works ok for me, I hope it works for you!
If you have setted previous params, you may use:
$this->paginate(null,$conditions)
This might be help full to someone....
This is how I did complicated joins with pagination in cakephp.
$parsedConditions['`Assessment`.`showme`'] = 1;
$parsedConditions['`Assessment`.`recruiter_id`'] = $user_id;
$this->paginate = array(
'conditions' => array($parsedConditions ),
'joins' => array(
array(
'alias' => 'UserTest',
'table' => 'user_tests',
'type' => 'LEFT',
'conditions' => '`UserTest`.`user_id` = `Assessment`.`testuser_id`'
),
array(
'alias' => 'RecruiterUser',
'table' => 'users',
'type' => 'LEFT',
'conditions' => '`Assessment`.`recruiter_id` = `RecruiterUser`.`id`'
)
,
array(
'alias' => 'OwnerUser',
'table' => 'users',
'type' => 'LEFT',
'conditions' => '`Assessment`.`owner_id` = `OwnerUser`.`id`'
)
),
'fields' => array('Assessment.id', 'Assessment.recruiter_id', 'Assessment.owner_id', 'Assessment.master_id', 'Assessment.title', 'Assessment.status', 'Assessment.setuptype','Assessment.linkkey', 'Assessment.review', 'Assessment.testuser_email', 'Assessment.counttype_2', 'Assessment.bookedtime', 'Assessment.textqstatus', 'Assessment.overallperc', 'UserTest.user_id', 'UserTest.fname', 'UserTest.lname', 'RecruiterUser.company_name', 'OwnerUser.company_name'),
'limit' => $limit,
'order'=> array('Assessment.endtime' => 'desc')
);