cakephp contain twice model association - cakephp

I have to fetch data from posts table
which has foreign keys (
category_id references to categories.id
created_by references to users.id,
updated_by references to users.id
)
I can fetch created_by username but not both
$this->Post->Behaviors->load('Containable');
$this->paginate = array(
'conditions' => array('Post.category_id' => $id),
'order' => array('title'),
'contain' => array(
'User'=>array(
'fields'=>array('id','first_name','last_name','username'),
'conditions' => array('User.id = Post.created_by')
),
//posts table has 2 fields(created_by & updated_by) associated with users table
//'User'=>array(
// 'fields'=>array('id','first_name','last_name','username'),
// 'conditions' => array('User.id = Post.updated_by')
// ),
'Category'=>array(
'Type'=>array(
'fields'=>array('id','type_name')
)
),
)
);
//post model
public $belongsTo = array(
'User'=> array(
'className' => 'User',
'foreignKey' => 'created_by',
'foreignKey' => 'updated_by'
),
);
//user model
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => array('created_by','updated_by'),
),
);
how to show both and alias both Users as (created_by & updated_by)

First you need to define two relationships in the Post model
public $belongsTo = array(
'CreatedUser'=> array(
'className' => 'User',
'foreignKey' => 'created_by'
),
'UpdatedUser'=> array(
'className' => 'User',
'foreignKey' => 'updated_by'
)
);
Now create the converse relationships in the User model.
public $hasMany = array(
'CreatedPosts' => array(
'className' => 'Post',
'foreignKey' =>'created_by'
),
'UpdatedPosts' => array(
'className' => 'Post',
'foreignKey' => 'updated_by'
),
);
Then the find()
$this->Post->Behaviors->load('Containable');
$this->paginate = array(
'conditions' => array('Post.category_id' => $id),
'order' => array('title'),
'contain' => array(
'CreatedUser'=>array(
'fields'=>array('id','first_name','last_name','username')
),
'UpdatedUser'=>array(
'fields'=>array('id','first_name','last_name','username')
),
'Category'=>array(
'Type'=>array(
'fields'=>array('id','type_name')
)
),
)
);

Related

Cakephp Find Recursive Associations

My Cakephp Application Has the following models with relations ships
class Category extends AppModel {
public $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'products_categories',
'foreignKey' => 'category_id',
'associationForeignKey' => 'product_id',
'unique' => 'keepExisting',
),
);
}
class Product extends AppModel {
public $primaryKey = 'id';
public $hasMany = array(
'ProductSwatch' => array(
'className' => 'ProductSwatch',
'foreignKey' => 'product_id',
'dependent' => true
),
'ProductDimension' => array(
'className' => 'ProductDimension',
'foreignKey' => 'product_id',
'dependent' => true
),
'ProductCare' => array(
'className' => 'ProductCare',
'foreignKey' => 'product_id',
'dependent' => true
),
'ProductDimension' => array(
'className' => 'ProductDimension',
'foreignKey' => 'product_id',
'dependent' => false,
),
'ProductCare' => array(
'className' => 'ProductCare',
'foreignKey' => 'product_id',
'dependent' => false,
),
'Review' => array(
'className' => 'Review',
'foreignKey' => 'product_id',
'dependent' => true,
)
);
}
When i am finding all the Category elements only Product Model contents are coming is there any way to get the Products associations(ProductDimension, ProductSwatches, etc) when we fetch the Categories model?
By default CakePHP 2 recursion level is 1st level association only.
You can use recursive option of find (or model property) to fetch deep associations.
For more information about model recursive property, see: http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive
For example:
$this->Category->find('all', array(
'recursive' => 2,
'conditions' => array(), // Your conditions, etc.
));
Another (and better way) is using Containable behaviour.
add
public $actsAs = array('Containable');
to your model(s) to enable Containable behaviour. Then you can use:
$this->Category->find('all', array(
'contain' => array(
'Product' => array(
'ProductSwatch',
'ProductDimension',
'ProductCare',
'Review',
),
),
'conditions' => array(), // Your conditions, etc.
));
to fetch deeper associations.
For more information about Containable behaviour and deeper associations, see http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#containing-deeper-associations

saveAll not working with hasMany through (Join Model)

I'm trying to do this with last 2.x CakePHP version
http://i.stack.imgur.com/IylLu.png
Without education_id in projects_students table works perfectly. But doesn't work with education_id.
this is my implementation with education_id:
ProjectsStudent.php
class ProjectsStudent extends AppModel {
public $belongsTo = array(
'Project' => array(
'className' => 'Project',
'foreignKey' => 'project_id'
),
'Student' => array(
'className' => 'Student',
'foreignKey' => 'student_id'
)
);
Student.php
public $hasMany = array('ProjectsStudent');
public $hasAndBelongsToMany = array(
'Education' => array(
'className' => 'Student',
'joinTable' => 'projects_students',
'foreignKey' => 'student_id',
'associationForeignKey' => 'project_id',
),
);
Project.php
public $belongsTo = 'Status';
public $hasMany = array(
'Doc' => array(
'className' => 'Doc',
'joinTable' => 'docs',
'foreignKey' => 'project_id',
),
'History' => array(
'className' => 'History',
'joinTable' => 'history',
'foreignKey' => 'project_id',
),
'ProjectsStudent'
);
public $hasAndBelongsToMany = array(
'Student' => array(
'className' => 'Student',
'joinTable' => 'projects_students',
'foreignKey' => 'project_id',
'associationForeignKey' => 'student_id',
),
'Professor' => array(
'className' => 'Professor',
'joinTable' => 'projects_professors',
'foreignKey' => 'project_id',
'associationForeignKey' => 'professor_id',
),
'Education' => array(
'className' => 'Education',
'joinTable' => 'projects_educations',
'foreignKey' => 'project_id',
'associationForeignKey' => 'education_id',
),
);
ProjectsController.php
$data = array(
'Project' => array(
'id' => $id,
'status_id' => 5,
'Student' => array($this->Auth->user('id'))),
'History' => array(
array(
'action' => 'update -> status 5',
'student_id' => $this->Auth->user('id'),
)
),
'ProjectsStudent' => array(array(
'education_id' => "5"))
);
$this->Project->saveAll($data, array('deep' => true))
Output error:
Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '109' for key 'PRIMARY'
SQL Query: INSERT INTO tfg.projects_students (project_id, education_id) VALUES (109, 5)
I think CakePHP is trying 2 inserts, with (project_id, student_id) and with (project_id, education_id)
I want just one input like INSERT INTO tfg.projects_students (project_id,student_id,education_id) VALUES (109, 1, 5)
Thanks in advance, sorry for my english.
---SOLUTION---
$data = array(
'Project' => array(
'id' => $id,
'status_id' => 5,
'Student' => array($this->Auth->user('id'))),
'History' => array(
array(
'action' => 'update -> status 5',
'student_id' => $this->Auth->user('id'),
)
),
);
$this->Project->saveAll($data, array('deep' => true));
$this->Project->ProjectsStudent->updateAll(
array('education_id' => $this->Auth->user('education')),
array('project_id' => $this->Project->id));
You appear to have setup the projects_students table to use project_id as the primary key. The primary key needs to be unique whereas the project_id foreign key is likely to be duplicated (as appears to be happening for you). The join table should be at least:-
id (int)
project_id (int)
student_id (int)
Where id is the primary key (with auto increment enabled).

Cakephp Find conditions on related table with hasAndBelongsToMany

I have the following code that gives an error from the moment I do a find condition on the associated Model (HABTM):
class Users extends Model{
public $useTable = 'users';
public $hasAndBelongsToMany = array(
'UserCategories' => array(
'className' => 'UserCategories',
'joinTable' => 'user_categories_link',
'foreignKey' => 'user_id',
'associationForeignKey' => 'category_id',
'unique' => false,
)
);
public function getData($page = 0, $category = '', $subcategory = ''){
return $this->find('all', array(
'limit' => 6,
'page' => $page,
'conditions'=> array(
'active'=> 1,
'UserCategories.category_name' => $category, // THIS GIVES ERROR
'UserCategories.category_subcategory' => $subcategory, // THIS GIVES ERROR
)
));
}
In my Controller:
$this->Users->getData(0, 'somemaincategory', 'somesubcategory');
I can't seem to do conditions on the related HABTM-Model (UserCategories in this case). I also tried to use 'contain' (with $actsAs), but then he stills gives me all the User data even if there is no Category linked with it. The Category array is in that case just blank.
Hope someone can help me.
Thanks in advance,
AƤron
Do a manual join. You can use this to do an actual inner join (contain will act as a left join). http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
$this->find('all',
array(
'conditions' => array(
'active' => 1,
),
'joins' => array(
array(
'table' => 'user_categories_link',
'alias' => 'UserCategoriesLink',
'type' => 'inner',
'conditions' => array(
'UserCategoriesLink.user_id = User.id'
),
),
array(
'table' => 'user_categories',
'alias' => 'UserCategories',
'type' => 'inner',
'conditions' => array(
'UserCategories.id = UserCategoriesLink.category_id',
'UserCategories.category_name' => $category,
'UserCategories.category_subcategory' => $subcategory,
),
)
),
)
);

CakePHP Simple table association assistance

I'm really struggling with a table association in cakephp, all I'm trying to do is associate two tables together, however one table has two two foreign keys to the other table.
For some reason, I cannot get any information to be displayed in the field select form for home_id ....
Please see the database picture below and the associated code.
I'm really new to cakephp but feel if I can nail this it will be really useful - any help is greatly appreciated.
Database Schema
class SafcTeam extends AppModel {
var $name = 'SafcTeam';
var $displayField = 'name';
var $validate = array(
'name' => array(
'notempty' => array(
'rule' => array('notempty'),
),
),
'badge' => array(
'notempty' => array(
'rule' => array('notempty'),
),
),
);
var $hasMany = array(
'SafcTeam' => array(
'className' => 'SafcEvent',
'foreignKey' => 'home_id',
)
);
}
class SafcEvent extends AppModel {
var $name = 'SafcEvent';
var $displayField = 'id';
var $validate = array(
'safc_matchtype_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'safc_league_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'home_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'away_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'streamer_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'safc_channel_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'comments' => array(
'notempty' => array(
'rule' => array('notempty'),
),
),
'safc_profile_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'safc_source_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'event_info_url' => array(
'notempty' => array(
'rule' => array('notempty'),
),
),
);
var $belongsTo = array(
'SafcMatchtype' => array(
'className' => 'SafcMatchtype',
'foreignKey' => 'safc_matchtype_id'
),
'SafcLeague' => array(
'className' => 'SafcLeague',
'foreignKey' => 'safc_league_id'
),
'SafcChannel' => array(
'className' => 'SafcChannel',
'foreignKey' => 'safc_channel_id'
),
'SafcProfile' => array(
'className' => 'SafcProfile',
'foreignKey' => 'safc_profile_id'
),
'SafcSource' => array(
'className' => 'SafcSource',
'foreignKey' => 'safc_source_id'
),
'SafcTeam' => array(
'className' => 'SafcTeam',
'foreignKey' => 'home_id'
)
);
}
you have to use an alias for each of this relation of your SafcTeam Model:
var $belongsTo = array(
//relationship for your home_id fk
'SafcHomeTeam' => array(
'className' => 'SafcTeam',
'foreignKey' => 'home_id'
),
//relationship for your away_id key
'SafcAwayTeam' => array(
'className' => 'SafcTeam',
'foreignKey' => 'away_id'
)
);
and also in the related safc team model :
var $hasMany = array(
'SafcHomeTeam' => array(
'className' => 'SafcEvent',
'foreignKey' => 'home_id',
),
'SafcAwayTeam' => array(
'className' => 'SafcEvent',
'foreignKey' => 'away_id',
)
);
In your SafcEvents controller in the action add and edit add this:
//to respect cake conventions need the select list to be plural (Teams <--- with a s at the end)
$safcHomeTeams = $this->SafcEvent->SafcHomeTeam->find('list');
$safcAwayTeams = $this->SafcEvent->SafcAwayTeam->find('list');
//also pass those list to the view
$this->set(compact('SafcAwayTeams', 'SafcHomeTeams));
In the safcevent view Add and Edit
in the form section :
//to respect cake convention to construct your select input properly
//you need to refere to the list established in the controller ($SafcHomeTeams by using $SafcHomeTeam_id <--singular + "_" + "id")
echo $this->Form->input('SafcAwayTeam_id');
echo $this->Form->input('SafcHomeTeam_id');
Cake does not support complex FK out the box, you can define a relation with conditions like so
public $hasMany = array(
'TheRelation' => array(
'foreignKey' => false,
'conditions' => array(
... conditions ...
)
)
)

cakephp habtm nested data

I have a HABTM relationship and I'd like to get nested data for a categories table from a product table something like this product array:
array(
(int) 0 => array(
'id' => (int) 1,
'name' => 'a',
'categories' => array(
(int) 0 => array(
'id' => (int) 1
),
(int) 1 => array(
'id' => (int) 2
)
)
),
(int) 1 => array(
'id' => (int) 2,
'name' => 'b',
'categories' => array(
(int) 0 => array(
'id' => (int) 1
)
)
)
)
Is this possible with cake?
EDIT: I will try to explain further what I want to do.
Please bear with me, I am new to cake and am having trouble getting to grips it.
I have a 'product' table:
public $hasAndBelongsToMany = array(
'Category' => array(
'className' => 'Category',
'joinTable' => 'categories_sculptures',
'foreignKey' => 'sculpture_id',
'associationForeignKey' => 'category_id',
'unique' => 'keepExisting'
)
)
and a category table:
public $hasAndBelongsToMany = array(
'Sculpture' => array(
'className' => 'Sculpture',
'joinTable' => 'categories_sculptures',
'foreignKey' => 'category_id',
'associationForeignKey' => 'sculpture_id',
'unique' => 'keepExisting'
)
);
and a category products table:
public $belongsTo = array(
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Sculpture' => array(
'className' => 'Sculpture',
'foreignKey' => 'sculpture_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
I would like to build a view table of the sculptures and also show in each row which categories each sculpture is in (which could be more than one). As I am new to cake I don't know how I would go about this. If I was just querying mysql I could get this information with a group_concat or a nested select, or inefficiently by looping through first array and querying the category_sculpture table by sculpture key and adding the results to the first array. But I would like to know the best way to get this result the cake way.
I have found the answer to my needs:
$this->Sculpture->recursive = 1;

Resources