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'
)
)
Related
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
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 !
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'
)
)
)
)
I am using these three relations User, Movie and UsersWatchlist.. Where users_watchlists contains movie_id and user_id as attributes.. I have this structure
array(
'User' => array(
'id' => '3'
),
'UsersWatchlist' => array(
'UsersWatchlist' => array(
(int) 0 => '3'
)
)
)
public function watchlist($id = null) {
$userid = '3';
if (!$id && $userid != 3) {
$this->Session->setFlash('Invalid Movie');
$this->redirect($this->referer(array('action' => 'listing')));
}
$this->request->data['User']['User'][] = $userid;
$this->request->data['Movie']['Movie'][] = $id;
debug($this->request->data);
if ($this->User->saveAll($this->request->data)) {
debug("saved");
$this->Session->setFlash('The movie has been added to your watchlist', 'admin/flash_success');
//$this->redirect($this->referer(array('action' => 'listing')));
} else {
debug("saved bo");
$this->Session->setFlash('The movie could not be added to your watchlist. Please, try again.', 'admin/flash_error');
//$this->redirect($this->referer(array('action' => 'listing')));
}
}
I used saveAll method on User but its not saving.. Please provide me solution to save the data..
In Movie model,
public $hasAndBelongsToMany = array('User' => array(
'className' => 'User',
'joinTable' => 'users_watchlists',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In User model,
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'users_watchlists',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In UsersWatchlist model,
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
The data array you're trying to save is wrong.
If you're saving throung the User model your structure should be:
array(
'User' => array(
'id' => '3'
),
'Movie' => array(
'Movie' => array(
(int) 0 => '3'
)
)
I know the title doesn't describe the best what I want to achieve, but I couldn't think of anything else.
Let's say I have the following array:
[Sender] => Array
(
[0] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 1
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 3
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
[1] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 3
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 2
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
)
I am using the ContainableBehaviour to cut off extra data.
My problem is: how do I filter out the Senders after a key which is present in PrivateMessagesUser? Say I need only the Sender where PrivateMessagesUser.recipient_id = 3.
I tried with
'Sender' => array(
'PrivateMessagesUser' => array(
)
),
but it didn't work. Looks like I have to get over the [0], [1]... keys somehow and I don't know how.
Any help would be appreciated!
EDIT
Here's how I obtain the array posted above:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()
),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
'PrivateMessagesUser' => array(
'fields' => array('PrivateMessagesUser.id')
//'conditions' => array('PrivateMessagesUser.recipient_id' => $this->Auth->user('id'))
)
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
);
How can I edit these lines in order to achieve the desired result?
EDIT 2
I am calling the paginate() from the PrivateMessagesController.
Associations:
User Model:
var $hasAndBelongsToMany = array(
'PrivateMessageSent' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'sender_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'PrivateMessageReceived' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'recipient_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
PrivateMessage Model:
var $hasAndBelongsToMany = array(
'Sender' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'sender_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Recipient' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'recipient_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
);
PrivateMessagesUser Model:
var $belongsTo = array(
'PrivateMessage' => array(
'className' => 'PrivateMessage',
'foreignKey' => 'private_message_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Sender' => array(
'className' => 'User',
'foreignKey' => 'sender_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Recipient' => array(
'className' => 'User',
'foreignKey' => 'recipient_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
And the database tables look like:
users: id, username, ...
private_messages: id, subject, ...
private_messages_users: id, private_message_id, sender_id, recipient_id, status, ...
There are three ways to achieve this.
Looking at your returned data array, I'm guessing PrivateMessagesUser belongsTo Sender.
1. Querying the PrivateMessagesUser model
Sometimes, all it takes is querying the right model. You can apply the conditions directly to the model you want to apply your restrictions on.
$this->Sender->PrivateMessagesUser->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender')
));
2. Applying conditions to related models
This doesn't work all the time, because CakePHP's SQL generation doesn't always work the way you want it to. But in simple cases like a hasMany relationship, you can use this:
$this->Sender->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('PrivateMessagesUser')
));
Again, this will work only if Cake executes a JOIN for the Containable parameters AND uses the conditions right.
3. Using joins
This method is foolproof but a little messy since it's highly customizable.
$this->Sender->find('all', array(
'joins' => array(
array(
'table' => 'private_messages_users',
'alias' => 'PrivateMessagesUser',
'type' => 'inner',
'conditions' => array(
'PrivateMessagesUser.sender_id = Sender.id',
'PrivateMessagesUser.recipient_id' => 3
)
)
)
));
My last piece of advice for you is to place this code into the Model. Follow the principle of "fat models, skinny controllers" whenever possible.
In the Sender model:
function fetchByRecipientId($recipientId) {
...
}
Good luck!
EDIT: In order to make this work for pagination, follow the methods above but use the following format:
$this->paginate = array(
'PrivateMessagesUser' => array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender'),
// 'order' => ... other keys if you wish
)
);
$this->set('senders', $this->paginate());
You can put conditions inside Containable, like so:
$this->Sender->find('all', array(
'contain' => array(
'PrivateMessagesUser' => array('conditions' => array('recipient_id' => 3))
)
));
EDIT:
Try modifying your $this->paginate as follow:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()//array of message id's
),
'fields' => array('PrivateMessagesUser.id'),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
)
Then call your paginate $this->paginate($this->PrivateMessage)