Create multiple models at once in cakephp - php

What I'm trying to reach is to register a User and a Firm at once. So I would need to insert into 3 tables: users, firms, and firms_users. CakePHP should do this automatically, because I've set the $hasAndBelongsToMany associtation in the models. But during the registration, only the users table gets written. Am I missing something?
registration form
<div class="users form">
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php
echo $this->Form->input('User.email', array('type' => 'email')); //standard HTML5 email validation
echo $this->Form->input('User.password');
echo $this->Form->input('Firm.0.name');
echo $this->Form->input('Firm.0.zipcode');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
the relevant part of User model
public $hasAndBelongsToMany = array(
'Firm' => array(
'className' => 'Firm',
'joinTable' => 'firms_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'firm_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
and the relevant part of Firm model
class Firm extends AppModel {
public $hasAndBelongsToMany = array('User'=>array('className'=>'User'));
finally the UsersController / show_reg_form action
public function show_reg_form(){
if ($this->request->is('post')) {
$this->loadModel('Firm');
$this->User->create();
$this->Firm->create();
if ($this->User->saveAll($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect(array('action' => 'loggedin','loggedin'));
}
$this->Session->setFlash(
__('The user could not be saved. Please, try again.')
);
}
}

I think this code will work
public function show_reg_form(){
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Firm->create();
if($this->Firm->save($this->request->data))
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect(array('action' => 'loggedin','loggedin'));
}
else{
$this->Session->setFlash(
__('The user could not be saved. Please, try again.')
);
}
}
}

It should be
echo $this->Form->input('Firm.name');
echo $this->Form->input('Firm.zipcode');

In order to save with hasAndBelongsToMany association you should have the array like this to save the records
Array
(
[User] => Array
(
[field_1] => 1
[field_2] => 2
[field_3] => 3
[field_4] => 4
)
[Firm] => Array
(
[0] => 5
[1] => 8
[2] => 4
)
)
where 5, 8, 4 are the record ids of firm table
I think This is not the case you're looking for,
I would suggest you to go through the
hasMany association if User has many firms public $hasMany = array('Firm');
hasOne association if User has only one firm public $hasOne = array('Firm');
so that it will add a Firm when a user is created

You can not save data in all three tables using only one saveAll.
First you need to save firm record then assign the new generated firm id as hidden field in $this->data and save user model data with saveAll. Then data will enter in third table named firms_users.
You can check the below link for more information
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm

Related

CakePHP select field does not populate

I'm Using cakePHP 2.3.8
I have two tables: application, computer_application. The relationship is one application hasMany computer_application, foreign key is application_id
in my ComputerApplication model:
class ComputerApplication extends AppModel{
public $name = "ComputerApplication";
public $useTable = "computer_application";
var $belongsTo = array(
'Computer' => array(
'className' => 'Computer',
'foreignKey' => 'computer_id',
'dependent' => true
),
'Application' => array(
'className' => 'Application',
'foreignKey' => 'application_id',
'dependent' => true
)
);
}
In my ComputerApplication controller. HERE I INITIALIZE THE POPULATION OF DROPDOWN in **add** function
public function add($id=null) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}
$this->set('computerApplications',
$this->ComputerApplication->Application->find('list',
array('fields' => array('description') ) ) );
}
Now In my Add View
echo $this->Form->create("computerApplication");
echo $this->Form->input('application_id',array('empty'=>''));
echo $this->Form->end('Save Post');
My problem is that it won't populate the select input. This is the first time I used 2 words in table [computer_application] using cake since I don't have problem populating other table with just one word. Just help me identify which I need to tweak for it to populate.
$this->set('applications', ...
and not
$this->set('computerApplications', ...

Cakephp joining two models on insert

OKay so i have two tables Employee and User
my employee model looks like this:
class Employee extends AppModel{
public $name = 'Employee';
public $primaryKey = "employee_id";
public $actsAs = array('Containable');
public $belongsTo = array(
'User' => array(
'className' => 'User',
'dependent' => false,
'foreignKey' => 'user_id'
)
);
}
And my user model looks like this:
App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {
// ...
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
}
return true;
}
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A username is required'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('employee', 'client')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
)
);
}
In my employee controller i have an action that allows employees to add other employees the action looks like this:
public function add() {
if ($this->request->is('post')) {
$this->Employee->User->create();
if ($this->Employee->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
My employee table looks like this
employee_id user_id
Now whenever i add a user the user is correctly added in my user table and a row is also added in my employee table however there are two mistakes in the employee table:
The employee_id is an auto increment this does not happen and it seems it keeps overriting 1. (so that every user i try to create is employee_id = 1)
the user_id is always 0 however in the user table the user_id is for example 21.
Can anyone tell me why this is happening and how i can fix it?
update
My add action in my employee controller now looks like this:
public function add() {
if ($this->request->is('post')) {
$this->Employee->User->create();
if ($this->Employee->User->saveAll($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
ive added a hasMany to my user model:
public $hasMany = array(
'Employee' =>array(
'className' => 'Employee',
'dependent' => true,
'foreignKey' => 'user_id'
)
);
Still no change
A few issues...
1) Your primary key for employees table should be id, not employee_id. Primary keys are always named id, according to cakephp conventions - http://book.cakephp.org/2.0/en/getting-started/cakephp-conventions.html
2) Just as you've got a belongsTo in your Employee model, you should also add a hasOne relationship to your user model - see http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasone
3) In order to save a record, along with it's related data, the method you want is saveAll - check out the documentation here: http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveall-array-data-null-array-options-array

cakephp insert data on database of linked models

I have two models "Ficha" and "Perigo":
class Ficha extends AppModel {
var $primaryKey = 'id_ficha';
public $validate = array(
'nome_produto' => array(
'rule' => 'notEmpty'
),
'versao' => array(
'rule' => 'notEmpty'
),
'data_ficha' => array(
'rule' => 'notEmpty'
)
);
}
class Perigo extends AppModel {
var $belongsTo = array(
'Ficha' => array(
'className' => 'Ficha',
'foreignKey' => 'id_fichas'
)
);
}
As you can see they are "linked". Now, in the code i have a form for Ficha that the method "add()" of FichasController redirects to my Perigo Model:
add() (of FichaController)
public function add() {
//pr($this->request->data); // to get the data from the form
if ($this->request->is('post')) {
$this->Ficha->create();
if ($this->Ficha->save($this->request->data)) {
$this->Session->setFlash('Your post has been saved.');
//$last_id=$this->Ficha->getLastInsertID();
//$this->redirect(array('action' => 'preencher_ficha'),$last_id);
$this->redirect(array('controller'=>'perigos', 'action' => 'add'),$last_id);
} else {
$this->Session->setFlash('Unable to add your post.');
}
}
}
The redirection is made to a form that exists in PerigosController.
add.ctp (of Perigo)
echo $this->Form->create('Perigo');
echo $this->Form->input('class_subst', array('label' => 'Classificação da substância ou mistura:'));
echo $this->Form->input('simbolos_perigo', array('label' => 'Símbolos de Perigo:'));
echo $this->Form->input('frases_r', array('label' => 'Frases R:'));
echo $this->Form->end('Avançar');
add() (of PerigoController)
public function add() {
if ($this->request->is('post')) {
$this->Perigo->create();
if ($this->Perigo->save($this->request->data)) {
$this->Session->setFlash('Your post has been saved.');
$this->redirect(array('controller'=>'perigos', 'action' => 'index'));
} else {
$this->Session->setFlash('Unable to add your post.');
}
}
}
but there's something i don't know how to do it. Since the models are relational, and the same happens with the two tables on the database (the table perigos has a foreignkey that is the primary key of the table "fichas", how can i insert the data on table perigos in database? I mean, how can i get the key of the Ficha inserted in the first form and insert her in the foreign key of "perigos" when i submit this second form?
As #mark says, your redirection is bad, it should include the id in the URL array:
$this->redirect(array('controller'=>'perigos', 'action' => 'add', $last_id));
Like this you are passing the parameter by URL.
In the add action of your PerigosController you should have an $idFicha param at the method:
//PerigosController.php
public function add($idFicha){
//here you can use $idFicha
...
//when submiting the Perigos form, we add the foreign key.
if($this->request->is('post')){
//adding the foreign key to the Perigo's array to add in the DB.
$this->request->data['Perigo']['ficha_id'] = $idFicha;
if ($this->Ticket->save($this->request->data)) {
//...
}
}
}
Data submitted by POST method in a form will be always contained in an array of this type: $this->request->data['Model_name']. In your case:
$this->request->data['Perigo']
Another way to do this, is using sessions if you prefer to hide the id value:
http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#sessions

cakePHP bind hasmany through relationship

Ok this is kind of hard to explain but I'll try my best.
I have 3 tables
companies products product_availabilities
--------- -------- ----------------------
id id id
name name company_id
product_id
buys (tinyint)
sells (tinyint)
And their models
class Company extends AppModel
{
public $name = 'Company';
public $hasMany = array(
'ProductAvailability'
);
class Product extends AppModel
{
public $name = 'Product';
public $hasMany = array(
'ProductAvailability'
);
class ProductAvailability extends AppModel
{
public $name = 'ProductAvailability';
public $belongsTo = array(
'Company',
'Product'
);
}
What I want to do is when I create a company, I want to be able to select products that the company buys or sells. I've seen an example of a hasMany through relationship in the book (http://book.cakephp.org/1.3/view/1650/hasMany-through-The-Join-Model) but they are creating the form from the "join table" controller. Is it possible to bind the productAvailability model to my company model to be able to select the products while creating the company?
Edit : Here is how I've done it. I know it is not optimal as there is a lot of looping involved but it works.
Company controller :
$products = $this->Company->ProductAvailability->Product->find('list', array('fields' => array('Product.id', 'Product.label')));
$this->set('products', $products);
if($this->request->is('post')){
if($this->Company->save($this->request->data)){
foreach($products as $product)
{
$tmpArray = array(
'company_id' => $this->Company->id,
'product_id' => $product['Product']['id']
);
foreach($this->request->data('BuyProducts.product_id') as $buyProduct)
{
if($buyProduct == $product['Product']['id'])
$tmpArray['buys'] = 1;
}
foreach($this->request->data('SellProducts.product_id') as $sellProduct)
{
if($sellProduct == $product['Product']['id'])
$tmpArray['sells'] = 1;
}
if(count($tmpArray) > 2)
{
$this->Company->ProductAvailability->create();
$this->Company->ProductAvailability->set($tmpArray);
$this->Company->ProductAvailability->save();
}
}
$this->Session->setFlash('Yay', 'success');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Nay', 'error');
}
}
Company add form :
<?php echo $this->Form->create('Company'); ?>
<?php echo $this->Form->input('name', array( 'div' => 'full-form')); ?>
<?php echo $this->Form->input('BuyProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>
<?php echo $this->Form->input('SellProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>
<?php echo $this->Form->end(array('label' => __('Save'), 'div' => 'center', 'class' => 'bouton-vert')); ?>
You have two options. Either let cakePHP do some magic with the hasAndBelongsToMany relationship or doing it manually which is necessary if you add attributes to the join table
1. CakePHP HABTM
Using the capabilities of CakePHP and making a straight forward solution I would make these changes:
Model
If one company has more than one product, and the products belong to many companies. It is a hasAndBelongsToMany relationship between Company<->Product
// company.php
...
var $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'companies_products',
'foreignKey' => 'company_id',
'associationForeignKey' => 'product_id',
'unique' => true,
)
);
...
// similar in product.php
Add the required table 'companies_products' in the database.
Controller
Then in the add function from the Company Controller there should be something like:
$products = $this->Company->Product->find('list');
$this->set(compact('products'));
View
Finally insert the products in the add.ctp, the select should allow multiple selections and let cakePHP do some magic, like this:
echo $this->Form->input('products', array(
'label' => 'Products to buy (Ctr+multiple choice)'
'type' => 'select',
'multiple' => true,
));
2. Manually
When the HABTM becomes more 'exotic' and includes some attributes like in your case 'buy' or 'sell' you need to do the manual way. This is in the Product Controller setting manually the fields before inserting them in the database. Something like:
foreach($availableProducts as $availableProduct ){
$this->Product->ProductAvailabilities->create();
$this->Product->ProductAvailabilities->set( array(
'company_id' => $this->Product->id,
'product_id' => $availableProduct['Product']['id'],
'buys' => $availableProduct['Product']['buy'],
'sells' => $availableProduct['Product']['sell']
// or however you send it to the controller
));
$this->Product->ProductAvailabilities->save();
}
Let's hope this helps you ...
you are planning a habtm-relationship (m:n) with the possibility to have extra fields in the join table. Even though this can be done with regular habtm I prefer the way you choose and implement the m:n as 1:n:1, which is simply the same and gives you more options when saving your data.
Here is a similar question and answer
As for your question: You can collect the the data from your products table like this:
$this->Company->ProductAvailability->Product->find('all', $params);
Also you might want to have a look at the containable-behaviour which is very useful for this use case:
$params['conditions'] = array(
'Company.id' => $id
);
$params['contain'] => array(
'ProductAvailability' => array(
'conditions' =>array(
'buys' => 1
),
'Product' => array(
'order' => array(
'name' => 'ASC'
)
)
)
);
$this->Company->find('all', $params);

CakePHP 2.0 Adding Related Data fails with missing database table

I'm trying to save data to two models (a model and related hasMany) simultaneously, and have had some success in a number of places in my app, however this approach doesn't seem to be working with tables/models which have underscored names, i.e.
//View Code
echo $this->Form->create('Product');
echo $this->Form->input('name',array('between' => '<br />'));
echo $this->Form->input('Component.0.text',array('between' => '<br />'));
echo $this->Form->end(__('Submit'));
//Controller Code
if ($this->Product->saveAssociated($this->request->data)) {
$this->Session->setFlash(__('The product has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The product could not be saved. Please, try again.'));
}
The above works fine, however I have a model ProductComponent (db table product_components)
//View Code
echo $this->Form->create('Product');
echo $this->Form->input('name',array('between' => '<br />'));
echo $this->Form->input('ProductComponent.0.text',array('between' => '<br />'));
echo $this->Form->end(__('Submit'));
//Controller Code
if ($this->Product->saveAssociated($this->request->data)) {
$this->Session->setFlash(__('The product has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The product could not be saved. Please, try again.'));
}
The form is picking this up correctly as it's showing a Textarea rather than a standard input, however when saveAssociated is run, I get the response:
Database table product__components for model ProductComponent was not found.
Why is cake looking for a table with a double underscored name?
Any ideas?
Update for Issem Danny:
public $hasMany = array(
'ProductComponent' => array(
'className' => 'Product_Component',
'foreignKey' => 'product_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
A few things:
If you have these three models: Product, Component, ProductComponent, it seems to me you're trying to setup hasAndBelongsToMany relations. Check out the cakephp docs.
Using Component as or in a model name seems confusing to me..
If you have a model for a table product_components: your model should be named "ProductComponent" without an underscore (cake will add that automatically). If you dont follow cake's conventions you can declare the "useTable" property. Your model should look like this:
Code:
// model
class ProductComponent extends AppModel {
public $name = "ProductComponent";
// Only needed when not following cake's conventions
public $useTable = "product_components";
// rest of model code ...
}
// And the hasmany relation
public $hasMany = array(
'ProductComponent' => array(
'className' => 'ProductComponent',
'foreignKey' => 'product_id'
)
);
Hope that helps, good luck.
Have you tried to use
$this->Product->saveAll($this->data))
Try this link SaveAll

Categories