I'm starting with CakePHP. I have very simple models:
- Users
- Companies
- CompaniesUsers (a hasMany through relation between Users and Companies)
I create a user, and when I login as this user, if there isn't any relation between User and Companies, I'm redirected to the add action of the Companies controller. This is all done, and working well.
My "big" problem is: When I save a company, I must save the company's data AND the relation between the current user and the created company. This all must be done inside a transaction, because I don't want "orphan" companies. But where should I put this code? Create a save() function in the Companies model and create the relation after saving? Create an afterSave() function in the Companies model? Put all the code in the CompaniesController's add action? I don't think this last option is a good idea, the bussiness logic must be in the model, isn't it?
I know that this must be a very basic question, but I'm new to CakePHP and to MVC.
This all must be done inside a transaction, because I don't want "orphan" companies
Use saveAssociated
CakePHP already provides a function which does exactly what you're asking for: saveAssociated (also accessible via saveAll)
Model::saveAssociated(array $data = null, array $options = array())
The options array has multiple keys, of most relevance:
atomic: If true (default), will attempt to save all records in a single transaction. Should be set to false if database/table does not support transactions.
As such there's no need for any extra code, simply call saveAssociated
where right now save
is being called.
Usage
Ensure the saved data is the right format for a hasMany through relationship - if in doubt it should be the same format as a find containing the same data:
class ExampleController extends AppController {
function example() {
$data = array(
'Company' => array(
'name' => 'My Company'
),
'CompaniesUser' => array(
'user_id' => 'My User Id'
)
);
$this->Company->saveAssociated($data);
}
}
This will either save the new company and the relation to the given user - or fail modifying nothing in the database.
The answer of your first question is that you don’t need to insert additional code into model, this can be done in controller like this
CompanyController.php
$datasource = $this->Company->getDataSource();
try{
$datasource->begin();
if(!$this->Company->save($data)
throw new Exception();
if(!$this->User->save($data_one)
throw new Exception();
$datasource->commit();
} catch(Exception $e) {
$datasource->rollback();
}
The answer for the second question is bit difficult. I personally feel that Cakephp is filled with bad practices. It should follow Fat Model and Skinny Controller Concept. If you want to code best practice of MVC, then model layer would contain all business logic unlike cake basic functions.