Cakephp pagination using contain produces "not associated" warning - cakephp

I've got the following models:
Run->hasMany ActualResult
ActualResult belongs to Status
When I view an ActualResult, Cake gets the corresponding Status without straight out of the box.
When I view a Run, I want to paginate the ActualResults. I have managed to get this to almost work with the following code in RunsController::view():
public function view($id = null) {
if (!$this->Run->exists($id)) {
throw new NotFoundException(__('Invalid run'));
}
$this->Run->contain ( 'Pack', 'User', 'Status');
$options = array('conditions' => array('Run.' . $this->Run->primaryKey => $id));
$run = $this->Run->find('first', $options);
$this->set('run', $run);
// Paginate the ActualResults
$this->paginate = array(
'contain' => array('Status'),
'order' => 'ActualResult.format',
'limit'=>5 ,
'conditions' => array('ActualResult.run_id' => $id)
);
$actualResults = $this->Paginator->paginate('ActualResult');
$this->set('actualResults',$actualResults);
}
The problem is that I get a warning:
Warning (512): Model "ActualResult" is not associated with model "Status" [CORE\Cake\Model\Behavior\ContainableBehavior.php, line 343
Something v. similar works for me in another model association, and as mentioned view() in ActualResultController works fine, so I am stumped.
Can anyone help?
Here are the model assocations:
In Run.php:
public $hasMany = array(
'ActualResult' => array(
'className' => 'actual_result',
'foreignKey' => 'run_id',
'dependent' => true,
'finderQuery' => 'SELECT ActualResult.*, Txn.name, Status.name FROM actual_results AS ActualResult, txns as Txn, codes AS Status WHERE ActualResult.run_id = {$__cakeID__$} and Txn.id = ActualResult.txn_id and (Status.code = ActualResult.status and Status.code_type = "ARS");'
)
);
In ActualResult.php
public $belongsTo = array(
'Run' => array(
'className' => 'Run',
'foreignKey' => 'run_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Status' => array(
'class`enter code here`Name' => 'Code',
'foreignKey' => 'status',
'conditions' => 'code_type = "ARS"',
'fields' => '',
'order' => ''
)
);

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')
);

Cakephp 2 retrieve data where condition depends on child table

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
));

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
));

Cake PHP - How to access a special Model found by Pagination?

I have the following Code to get a special model related to another model related to actual object: (I want the Entry-model - in the Rubric-model-view)
$this->paginate = array(
'Entrieslocation' => array(
'conditions' => array('Entrieslocation.rubric_id' => $this->Rubric->id, 'Entrieslocation.subrubric_id' => '0'),
'joins' => array(
array(
'alias' => 'Entry',
'table' => 'entries',
'type' => 'INNER',
'conditions' => 'Entry.id = Entrieslocation.entry_id'
)
)
)
);
Then I thought I could get it by something like this:
$this->set('entries', $this->paginate('Entry'));
But the variable is empty, how can I access the Entries inside the Pagination in the view?
The Query generated by the code above is correct, I checked it by entering the query into phpmyadmin. So how can I access the result (only the Entries)?
Thanks for your help :)
First of all you must define $paginate variable below controller class. For example
class UsersController extends AppController {
public $paginate = array();
}
Then in your action follow following patter to get the paginated result.
$this->paginate = array(
'recursive' => -1,
'limit' => 10,
'conditions' => array('Your conditions'),
'fields' => array('Entry.*, Entrieslocations.*'),
'joins' => array(
array(
'table' => 'Entrieslocations',
'alias' => 'Entrieslocation',
'type' => 'inner',
'conditions' => 'Entry.id = Entrieslocation.entry_id'
),
),
'order' => array(
'Entry.id' => 'desc'
)
);
$entries = $this->paginate('Entry');
To pass result set to the view use following:
$this->set('entries', $entries);

CakePhp: On the fly associations using a re-named Model field?

I'm trying to use on the fly associations to trim down the data I retrieve, but the model I'm using is associated to other models with a re-named field because I have 2 of the same models associated with it.
So, here's the model, say 'test', that has two 'user' fields, both related to the User model.
In the model:
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
),
'User_Watched' => array(
'className' => 'User',
'foreignKey' => 'user_id_watched'
)
);
When I retrieve data related to 'test', I want to only retrieve particular data linked to the 'User' and 'User_Watched' fields without any other nested information.
But when I do:
$this->User->unbindModel(array('hasMany' => array('something1', 'something2')), false);
then something1 and something2 data does not show up for the 'User' field of model 'test', but is still retrieved for the 'User_watched' field.
Can I not retrieve unwanted data for the 'User_watched' field?
Hope this makes sense... :)
KcYxA,
Containable behavior might help a lot in this case, as benjamin mentioned, your "find" queries would look like:
$this->User->find('first', array(
'conditions' => array('User.id' => $id),
'contain' => array('UserWatched')
));
In this case, you won't have to use unbindModel method. In this example, you'll get User and UserWatched data.
If you need only User data from "find", then tell Cake to "$this->User->contain();" so it won't go further then User model.
to use on the fly associations to trim
down the data I retrieve
Good idea.
'foreignKey' => 'user_id_watched'
should possibly be:
'foreignKey' => 'user_watched_id'.
Edit 1: At least this would make sense according to my current understanding. If user_id is a correct foreign key(FK), which cakephp uses to unbind the relations, but user_id_watched isn't, than your described behavior is explained.
Edit 2: The Containable behavior gives you another tool for controlling associated models.
Change $primaryKey in fly, run controller
Sample:
// Models
//....
class PreProductoDescripcion extends AppModel {
/**
* Primary key field
*
* #var string
*/
public $primaryKey = 'id_producto_descripcion';
//....
//....
}
class SenasaPedidosDetalles extends AppModel {
/**
* Display field
*
* #var string
*/
public $displayField = 'cod_tango';
public $belongsTo = array(
'SenasaPedidos' => array(
'className' => 'SenasaPedidos',
'foreignKey' => 'senasa_pedidos_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'PreProductoDescripcion' => array(
'className' => 'PreProductoDescripcion',
'foreignKey' => 'cod_tango',
//'conditions' => array('SenasaPedidosDetalles.cod_tango' => 'PreProductoDescripcion.codigo'),
'fields' => '',
'order' => ''
)
);
//....
#
// Controller Fly
//...
$this->SenasaPedidos->Behaviors->load('Containable');
$this->SenasaPedidos->SenasaPedidosDetalles->PreProductoDescripcion->primaryKey = 'codigo';
$datos = $this->SenasaPedidos->find(
'first', array(
'fields' => array( 'SenasaPedidos.*' ),
'conditions' => array( 'SenasaPedidos.id' => $id ),
'contain' => array(
'Usuarios' => array(
'fields' => array( 'Usuarios.apellido_nombre' )
),
'Clientes' => array(
'fields' => array( 'Clientes.razon_social' )
),
'Provincias' => array(
'fields' => array( 'Provincias.nombre' )
),
'Transportes' => array(
'fields' => array( 'Transportes.razon_social' )
),
'SenasaPedidosDetalles' => array(
'fields' => array( 'SenasaPedidosDetalles.*' ),
'PreProductoDescripcion' => array(
'fields' => array(
'PreProductoDescripcion.id_producto_descripcion',
'PreProductoDescripcion.descripcion'
)
)
),
)
));
//...

Resources