Cake PHP HABTM relationship with same model - cakephp

I have a products table and a products_relateds table. This holds 2 references to products (product_id and related_id)
I'm trying to set up a HABTM relationship for this like so in my Product Model
public $hasAndBelongsToMany = array(
'Related' => array(
'className' => 'Product',
'joinTable' => 'products_relateds',
'foreignKey' => 'product_id',
'associationForeignKey' => 'related_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Does this look right? Do i need to create a Related model?
I get no errors, and viewing the products page will not load when this relationship is in place

That code is fine, your error must be elsewhere. Using $this->Product->findBy(1) should return something like this:
array(
'Product' => array(
'id' => '1',
'name' => 'Test 1'
),
'Related' => array(
0 => array(
'id' => '2',
'name' => 'Test 2',
'ProductsRelated' => array(
'id' => '3',
'product_id' => '1',
'related_id' => '2'
)
),
1 => array(
'id' => '3',
'name' => 'Test 3',
'ProductsRelated' => array(
'id' => '1',
'product_id' => '1',
'related_id' => '3'
)
)
)
)

Related

CakePHP 2.8 saveAll Creates Two Records Instead of One

I'm cloning a milestone record with associated data. I first find the data from the source milestone, then change the contents of the array and remove all 'id' fields. Then I attempt a 'saveAll'. All the associated data is being created properly but the 'milestones' table now has 2 new records instead of 1. The second record contains the ID used by the associated data, so why does the first record even exist?
The Data (simplified) and Call:
$test = array(
'Milestone' => array(
'name' => 'Clone Test',
'customer_status' => '',
'time_to_complete' => '1',
'is_active' => true,
),
'MilestoneAlert' => array(
(int) 0 => array(
'name' => 'Clone Test',
'type' => 'customer',
'milestone_alert_type_id' => '0',
'email' => null,
'subject' => 'First alert!',
'message' => 'Add a message',
'recipient_name' => '',
'is_active' => true,
),
(int) 1 => array(
'name' => 'Clone Test 1',
'type' => 'customer',
'milestone_alert_type_id' => '0',
'email' => null,
'subject' => 'Second alert!',
'message' => 'Add a message',
'recipient_name' => '',
'is_active' => true,
)
),
'MilestoneCondition' => array(
(int) 0 => array(
'name' => 'Clone Test',
'condition' => 'First condition.',
'is_active' => true,
),
(int) 1 => array(
'name' => 'Clone Test 1',
'condition' => 'Second condition.',
'is_active' => true,
)
)
);
$this->loadModel('Milestone');
$this->Milestone->create();
$this->Milestone->saveAll($test);
In Model/Milestone.php:
public $hasMany = array(
'MilestoneAlert' => array(
'className' => 'MilestoneAlert',
'foreignKey' => 'milestone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'MilestoneCondition' => array(
'className' => 'MilestoneCondition',
'foreignKey' => 'milestone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => 'MilestoneCondition.order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
In Model/MilestoneAlert.php:
public $belongsTo = array(
'Milestone' => array(
'className' => 'Milestone',
'foreignKey' => 'milestone_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In Model/MilestoneCondition.php:
public $belongsTo = array(
'Milestone' => array(
'className' => 'Milestone',
'foreignKey' => 'milestone_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
After running the method, there are two records in 'milestone_conditions', two records in 'milestone_alerts', and two identical records in 'milestones'. How do I keep it from creating two 'milestone' records?
Try to get the original data like this:
$test= $this->Milestone->findById('insert your id');
$this->Milestone->create(); // Create a new record
$this->Milestone->saveAll($test,array('deep' => true)); // And save it

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 deep conditions from controller

I am trying to get records from CoursesEmployee model within my BusinessesController. They are not linked directly which is my problem.
Each Business has Employees which can enrol in courses.
BusinessesController.php:
$options = array(
'conditions' => array('Business.' . $this->Business->primaryKey => 1)
);
$test = $this->Business->find('all', $options);
debug($test);
The output:
array(
(int) 0 => array(
'Business' => array(
'id' => '1',
'name' => 'Test Business',
),
'Employee' => array(
(int) 0 => array(
'id' => '1',
'business_id' => '1',
'name' => 'Keith Power',
'Business' => array(
'id' => '1',
'name' => 'Test Business',
),
'Course' => array(
(int) 0 => array(
'id' => '1',
'name' => 'Manual Handling',
'CoursesEmployee' => array(
'id' => '1',
'employee_id' => '1',
'course_id' => '1',
'course_module_id' => '1',
'completed' => true
)
),
(int) 1 => array(
'id' => '3',
'name' => 'Induction',
'CoursesEmployee' => array(
'id' => '2',
'employee_id' => '1',
'course_id' => '3',
'course_module_id' => '0',
'completed' => false
)
)
)
)
)
)
)
I wish to get the list of CoursesEmployee where CoursesEmployee.completed = true and Business.id = 1
Model Associations:
Business $hasMany Employee
Employee $belongsTo Business
Employee $hasAndBelongsToMany Course
public $hasAndBelongsToMany = array(
'Course' => array(
'className' => 'Course',
'joinTable' => 'courses_employees',
'foreignKey' => 'employee_id',
'associationForeignKey' => 'course_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
CoursesEmployee
public $belongsTo = array(
'Employee' => array(
'className' => 'Employee',
'foreignKey' => 'employee_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Course' => array(
'className' => 'Course',
'foreignKey' => 'course_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
cakephp 2.5
I suggest this way, if it doesn't work we'll try join way :
updated :
$coursesEmployes = $this->Business->Employee->CoursesEmployee->find('all',array(
'conditions'=>array('CoursesEmployee.completed '=> 'true' ,'Employee.business_id' => '1' ),
'recursive'=>3)
);
Hope it helps !

HABTM Just main model is saved with saveall()

I'm having problems with HABTM + cakephp.
In my app i have this models (with relation definition):
Cliente:
public $hasAndBelongsToMany = array(
'TiposComercio' => array(
'className' => 'TiposComercio',
'joinTable' => 'tipos_comercio_cliente',
'foreignKey' => 'cliente',
'associationForeignKey' => 'tipo_comercio'
)
);
TiposComercio:
public $hasAndBelongsToMany = array(
'Cliente' => array(
'className' => 'Cliente',
'joinTable' => 'tipos_comercio_cliente',
'foreignKey' => 'tipo_comercio',
'associationForeignKey' => 'cliente'
)
);
When the form is posted, i have in array $this->request->data this:
array(
'Cliente' => array(
'password' => '*****',
'razao_social' => 'Teste',
'responsavel' => 'responsavel',
'cidade' => '1',
'cep' => '13560201',
'logradouro' => 'Log test',
'numero' => '',
'bairro' => '',
'complemento' => '',
'atividades' => '',
'username' => 'username11',
'TiposComercio' => array(
(int) 0 => '1',
(int) 1 => '4'
)
)
)
When i execute $this->Cliente->saveAll($this->request->data); in ClientesController I have the following problem:
Just Cliente data is saved. Nothing of TiposComercio is saved.
What's wrong?
Thanks!
The structure of your data array seems to be wrong. Have a look at the manual for saving HABTM data: http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Based on the example, your data array should be formed like this:
array(
'Cliente' => array(
'password' => '*****',
'razao_social' => 'Teste',
'responsavel' => 'responsavel',
'cidade' => '1',
'cep' => '13560201',
'logradouro' => 'Log test',
'numero' => '',
'bairro' => '',
'complemento' => '',
'atividades' => '',
'username' => 'username11',
),
'TiposComecio' => array(
(int) 0 => '1',
(int) 1 => '4'
)
)

Cakephp: associations of associations in "fields"

a post has a user (belongsTo) and a user has a profile (hasOne). Normally everything works: I can access from Post to User and from User to Profile.
From Post, all works using a generic Find. The result is more or less this (I deleted some keys, just for example):
array(
'Post' => array(
'id' => '1',
'category_id' => '1',
'user_id' => '1',
'title' => 'Example',
'text' => '',
),
'User' => array(
'password' => '*****',
'id' => '1',
'group_id' => '1',
'username' => 'mirko',
'status' => 'active',
'Profile' => array(
'id' => '1',
'user_id' => '1',
'first_name' => 'Mirko',
'last_name' => 'Pagliai',
),
)
)
The problem comes when I use "fields", when I want to extract only a few fields.
For example, this works:
'fields' => array('id', 'title', 'User.id')
and the result is:
array(
'Post' => array(
'id' => '1',
'title' => 'Articolo di prova :-)'
),
'User' => array(
'id' => '1'
)
)
But I don't understand, always using "fields", how to access Profile.
These don'yt work:
'fields' => array('id', 'title', 'User.id', 'Profile.id')
'fields' => array('id', 'title', 'User.id', 'User.Profile.id')
I always get this error "Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'User.Profile.id' in 'field list'".
What's wrong? Thanks.
EDIT:
I'm not using the Containable behavior. Maybe is this the problem? Is it essential in this case?
An example, using paginate:
$this->paginate = array(
'conditions' => $conditions,
'fields' => array('id', 'title', 'User.id', 'Profile.id'),
'limit' => 10,
'recursive' => 2,
);
EDIT2:
thanks to #Hoff, I am close to the solution. But there is still something wrong (and Containable is very useful!).
In AppModel.php I added:
...
class AppModel extends Model {
public $actsAs = array('Containable');
public $recursive = -1;
...
But this doesn't work:
$this->paginate = array(
'conditions' => $conditions,
'contain' => array(
'User' => array(
'fields' => array('id'),
'Profile' => array(
'fields' => array('id', 'full_name'),
),
),
'Category' => array(
'fields' => 'title',
),
),
'fields' => array('id', 'user_id', 'category_id', 'title', 'created', 'modified', 'published'),
'limit' => 10,
);
Cause I get:
array(
(int) 0 => array(
'Post' => array(
'id' => '1',
'user_id' => '1',
'category_id' => '1',
'title' => 'Articolo di prova :-)',
'created' => '2012-06-21 18:46:00',
'modified' => '0000-00-00 00:00:00',
'published' => true
),
'Category' => array(
'title' => 'prova',
'id' => '1'
),
'User' => array(
'id' => '1'
)
)
)
but if I add any field to User (email, username, password, etc.), this works:
'User' => array(
'fields' => array('id', 'username'),
'Profile' => array(
'fields' => array('id', 'full_name'),
),
),
And I get:
array(
(int) 0 => array(
'Post' => array(
'id' => '1',
'user_id' => '1',
'category_id' => '1',
'title' => 'Articolo di prova :-)',
'created' => '2012-06-21 18:46:00',
'modified' => '0000-00-00 00:00:00',
'published' => true
),
'Category' => array(
'title' => 'prova',
'id' => '1'
),
'User' => array(
'id' => '1',
'username' => 'mirko',
'Profile' => array(
'id' => '1',
'full_name' => 'Mirko Pagliai'
)
)
)
)
Instead of using the 'recursive' key, I highly suggest using the containable behavior. The documentation on the behavior can be found here. I would suggest applying the behavior in your AppModel so you don't need to add it to all your models. In Model/AppModel.php:
App::uses('Model', 'Model');
class AppModel extends Model {
public $actsAs = array('Containable');
public $recursive = -1;
}
Then, for your pagination:
$this->paginate = array(
'conditions' => $conditions,
'fields' => array('id', 'title'),
'limit' => 10,
'contain' => array(
'User' => array(
'fields' => array('id'),
'Profile' => array(
'fields' => array('id')
)
)
)
);

Resources