Hi I have a site develop in cakephp.
I have two tables:
Ingredient
Property
The relation between the tables is HasAndBelongsToMany(HABTM).
This is my model:
class Ingredient extends AppModel {
public $name = 'Ingredient';
public $useTable = 'ingredients';
public $belongsTo = 'User';
public $hasAndBelongsToMany = array (
'Property' => array (
'className' => 'Property',
'joinTable' => 'ingredients_properties',
'foreignKey' => 'ingredient_id',
'associationForeignKey' => 'property_id',
'unique' => false
)
);
}
class Property extends AppModel{
public $name = 'Property';
public $useTable = 'properties';
}
Into my IngredientController I have to add a new Property I have tried in this mode:
$this->Ingredient->Property->create();
$this->Ingredient->Property->set('user_id',$this->Session->read('Auth.User.id'));
$this->Ingredient->Property->set('ingredient_id',$ing['IngredientAlias']['ingredient_id']);
if ($this->Ingredient->Property->save($this->request->data)){
$this->set('flash_element','success');
$this->Session->setFlash ('Ingrediente modificato con successo.');
$this->redirect(array('action'=>'edit',$alias));
}
else{
$this->set('flash_element','error');
$this->Session->setFlash('Errore di salvataggio activity');
}
Into the database insert a new record but If I want that is relation between the ingredients with insert a record in ingredients_properties(table of join), how can I do that? In this mode is like Ingredients hasMany Properties but is not correct.
How can I solve it?
Or I have to create the record into ingredients_properties manually?
You can take a look at the following link to achieve the same:
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
The solution is that:
class Ingredient extends AppModel {
public $name = 'Ingredient';
public $useTable = 'ingredients';
public $belongsTo = 'User';
public $hasAndBelongsToMany = array (
'Property' => array (
'className' => 'Property',
'joinTable' => 'ingredients_properties',
'foreignKey' => 'ingredient_id',
'associationForeignKey' => 'property_id',
'unique' => false
)
);
}
class Property extends AppModel{
public $name = 'Property';
public $useTable = 'properties';
public $hasAndBelongsToMany = array (
'Ingredient' => array (
'className' => 'Ingredient',
'joinTable' => 'ingredients_properties',
'foreignKey' => 'property_id',
'associationForeignKey' => 'ingredient_id',
'unique' => false
)
);
}
Related
I have a blog post model:
App::uses('AppModel', 'Model');
class BlogPost extends AppModel {
public $primaryKey = "ID";
public $useDbConfig = 'dev_blog';
public $useTable = 'posts';
public $hasMany = array(
'BlogComment' => array(
'foreignKey' => 'comment_post_ID',
'className' => 'BlogComment',
'order' => 'BlogComment.comment_date DESC',
'conditions' => array(
'BlogComment.comment_approved' => '1',
'BlogComment.comment_parent' => 0
)
)
);
}
And a blog comment model:
App::uses('AppModel', 'Model');
class BlogComment extends AppModel {
public $primaryKey = "comment_ID";
public $useDbConfig = 'dev_blog';
public $useTable = 'comments';
public $hasMany = array(
'Children' => array(
'className' => 'BlogComment',
'foreignKey' => 'comment_parent',
'order' => 'Children.comment_date DESC',
'conditions' => array(
'Children.comment_approved' => 1
)
)
);
}
In the controller, I set recursion on BlogPost equal to 2 and did a find:
$options = array(
'conditions' => array(
'BlogPost.ID' => $postID,
'BlogPost.post_status' => 'publish'
),
);
$post = $this->BlogPost->find('first', $options);
What this does is get the content of a particular blog post, all root comments and one level of replies to the root comments. It doesn't get a reply to a reply, though. How can I retrieve an arbitrary depth of replies?
Just don't use recursive at all. Ever.
Set it to -1 in the AppModel:
public $recursive = -1;
Then forget you even heard of it, and use CakePHP's awesome Containable Behavior to get the data you need.
Note: See the MANY other answers related to using CakePHP's Containable.
i'm new in CakePHP and i'm having problems in an example i'm building to learn.
I'm building a plugin with 3 models (Categoria,Plato,Imagen)
The relationships between them are the following:
Categoria - Plato (n-n)
Plato - Imagen (1-n)
If I go to Plato view, I get all Imagen by the relationship, but when I access through a category, I can't just reach the Imagen associated with each Plato. Why? What's the problem?
Models code:
Plato:
App::uses('AppModel', 'Model');
class Plato extends ErestaurantAppModel {
public $name = 'Plato';
//public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Categoria' => array(
'className' => 'Categoria',
'joinTable' => 'categorias_platos',
'foreignKey' => 'plato_id',
'associationForeignKey' => 'categoria_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
public $hasMany = array('Imagen' =>
array('foreingkey' => array('plato_id')));
}
Categoria:
App::uses('AppModel', 'Model');
class Categoria extends ErestaurantAppModel {
public $name = 'Categoria';
//public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Plato' => array(
'className' => 'Plato',
'joinTable' => 'categorias_platos',
'foreignKey' => 'categoria_id',
'associationForeignKey' => 'plato_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
}
Imagen:
App::uses('AppModel', 'Model');
class Imagen extends ErestaurantAppModel {
public $name = 'Imagen';
//public $actsAs = array('Containable');
public $belongsTo = array('Plato');
}
Finally, the code I'm launching when i go to a Categoria view.
App::uses('AppController', 'Controller');
class CategoriasController extends ErestaurantAppController {
public $uses = array('Erestaurant.Categoria');
public function index() {
$this->Categoria->recursive = 0;
$this->set('data', $this->Categoria->find('all'));
}
public function view($id = null) {
if (!$this->Categoria->exists($id)) {
throw new NotFoundException(__('Registro inválido.'));
}
/*
$this->Categoria->recursive = -1;
$options = array('conditions' =>
array('Categoria.'.$this->Categoria->primaryKey => $id),
'contain' => array(
'Plato' => array(
'Imagen'
)
)
);
*/
$this->Categoria->recursive = 2;
$options = array('conditions' =>
array('Categoria.'.$this->Categoria->primaryKey => $id));
$this->set('item', $this->Categoria->find('first', $options));
}
}
The commented code you see it's another way I tried, using Containable, but at the end I get error "Plato is not associated with model Imagen"
Database seems all ok, with each table created as needed (categorias, platos, imagens, categorias_platos) and with all foering keys created and trying to keep CakePHP default names.
Thank you!
To access deep relations you must use containable behavior. You have a definition of containable behavior in your model, but for some reason it is commented.
public $actsAs = array('Containable');
Uppon uncommenting this line in your Categoria, you can access deep relations in this way:
$this->Categoria->find('all', array(
'contain'=>array(
'Plato.Imagen'
)
));
...or something like this. For more information plase visit this link Containable Behavior
I have a Product model and an Image model. They have an HABTM association.
Some Images exist but they are not linked to the product.
Now when I save a Product I would like to link it to some unlinked images using an array of images IDs (I MUST use this array).
Here's my code:
class Image extends AppModel {
public $useTable = 'images';
var $hasAndBelongToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'products_images',
'foreignKey' => 'id_image',
'associationForeignKey' => 'id_product'
)
);
}
class Product extends AppModel {
public $useTable = 'products';
var $hasAndBelongToMany = array(
'Image' => array(
'className' => 'Image',
'joinTable' => 'products_images',
'foreignKey' => 'id_product',
'associationForeignKey' => 'id_image'
)
);
}
class productsController extends AppController {
public $name = 'Products';
public $uses = array('Products', 'File');
public function add() {
if (!empty($this->data)) {
$this->Product->create();
if ($this->AnnuncioImmobiliare->save($this->request->data)) {
$idProduct = $this->Product->getLastInsertID();
$this->request->data['imagesIds'] = array("1", "2", "3");
if(isset($this->request->data['imagesIds'])){
foreach($this->request->data['imagesIds'] as $imageId){
$this->Image->id = $imageId;
$this->Image->save(array('Product'=>array('id'=>$idProduct)));
}
}
}
}
}
}
This doesn't work. Where am I wrong?
1) you didn't provide the data, so we can't verify it's in the correct format.
2) you're using "save()" not "saveAll()" or "saveMany()" or "saveAssociated()". Just using "save()" will not save any associated model data.
I found a solution myself!
I observed how CakePHP handles $this->data->response array when data is passed using an input automagically created for HABTM associations and I found the array should be formatted like this:
array(
'Product' => array(
'name' => 'myProduct',
'id' => ''
),
'Image' => array(
'Image'=>array(
0 => '1',
1 => '2',
2 => '3'
)
)
)
So the correct code for the controller is
class productsController extends AppController {
public $name = 'Products';
public $uses = array('Products', 'File');
public function add() {
if (!empty($this->data)) {
$this->Product->create();
if (isset($this->request->data['imagesIds'])) {
$this->request->data['Image'] = array('Image' => $this->request->data['imagesIds']);
}
if ($this->AnnuncioImmobiliare->save($this->request->data)) {
/* success */
}
}
}
}
That's it! I hope you find this useful.
sorry for my english and i'm new using CAKEPHP 2.3
i get a problem using model association where i can't get "joined data" ( i understand that cakephp get automatically joined data if models are set good , obviously i make it wrong )
I have 2 tables in my database:
departements (with the following columns)
-id
-name
-region_id ( region_id is a foreign key on regions(id) )
regions (with the following columns)
-id
-name
i make two models in cakePhp:
Region.php
<?php
class Region extends AppModel {
var $name = 'Region';
var $actsAs = array( 'Containable' );
public $hasMany = array(
'Departement' => array(
'className' => 'Departement',
'foreignKey' => 'region_id',
'dependent' => false
)
);
}
?>
Departement.php
<?php
class Departement extends AppModel {
var $name = 'Departement';
var $actsAs = array( 'Containable' );
public $belongsTo=array(
'Region' => array(
'className' => 'Region',
'foreignKey' => 'region_id',
'dependent' => false
)
);
}
?>
in a another controller where i need departements and regions, i tryed many thinks but after yours i need your help please !!!
i make this :
first attempt:
<?php
class SignalementsController extends AppController {
public $helpers = array('Html', 'Form');
var $name = 'Signalements';
var $uses = array('Signalements','Regions','Departements','Communes');
public $recursive = 4;
public function index() {
$departements = $this->Departements->find('all');
$this->set('departements', $departements);
}
}
who output in the index view:
array(
(int) 0 => array(
'Departements' => array(
'id' => '1',
'name' => 'AIN',
'region_id' => '82'
)
),
(int) 1 => array(
'Departements' => array(
'id' => '10',
'name' => 'AUBE',
'region_id' => '21'
)
)
...
)
but there is no region joined automatically
second attempt: i change the find models from
$regions = $this->Regions->find('all');
$this->set('regions', $regions);
who output :
array(
(int) 0 => array(
'Regions' => array(
'id' => '11',
'name' => 'ILE-DE-FRANCE'
)
), ... );
but there is no departements joined automatically
last
$fields=array('Region.id','Region.nom','Departement.id','Departement.nom');
$all= $this->Regions->Departements->find('all',$fields);
/* or all this not working as execpted
$all= $this->Departements->Regions->find('all',$fields);
$all= $this->Departements->find('all',$fields);
$all= $this->Regions->find('all',$fields);
*/
$this->set('all', $all);
i try to get the regions data inside each departemts for exemple like this
array(
(int) 0 => array(
'Departements' => array(
'id' => '1',
'nom' => 'AIN',
'region' => array( 'id' => '82', 'nom' => 'POITOU-CHARENTES')
)
),
but i get only this :
array(
(int) 0 => array(
'Departements' => array(
'id' => '1',
'nom' => 'AIN',
'region_id' => '82'
)
),
If you have any idea please leave it
thank you very much
You are using Containable behaviour in your model, so try the find with this:
$departements = $this->Departement->find('all', array('contain' => 'Region'));
Also the maximum level for recursive is 2, setting it to 4 (or 1000) has the effect of 2.
Your ID is of type varchar and should be int.
Also, here is a stripped down version of your code
Region.php
<?php
class Region extends AppModel {
var $actsAs = array( 'Containable' );
public $hasMany = array( 'Departement' );
}
?>
Departement.php
<?php
class Departement extends AppModel {
var $actsAs = array( 'Containable' );
public $belongsTo=array( 'Region' );
}
?>
<?php
class SignalementsController extends AppController {
public $helpers = array('Html', 'Form');
var $uses = array('Signalements','Regions','Departements','Communes');
public function index() {
$this->Departement->recursive = 1;
$departements = $this->Departements->find('all');
$this->set('departements', $departements);
}
}
index.ctp
<?php print_r($departements); ?>
What does it give you?
I got this models:
class CompanyRestaurantRequest extends AppModel
{
public $name = "CompanyRestaurantRequest";
//public $actsAs = array('Containable');
public $hasMany = array(
"UserRestaurantRequestFeed" => array(
'dependent' => true
)
);
}
class UserRestaurantRequestFeed extends AppModel{
public $name = "UserRestaurantRequestFeed";
public $belongsTo = array("CompanyRestaurantRequest");
public $hasMany = array("UserRestaurantRequestFeedResponse");
}
class UserRestaurantRequestFeedResponse extends AppModel{
public $name = "UserRestaurantRequestFeedResponse";
public $belongsTo = array("UserRestaurantRequestFeed");
}
and I am trying to paginate CompanyRestaurantRequest like this:
$this->CompanyRestaurantRequest->recursive = 5;
$this->CompanyRestaurantRequestFeed->recursive = 5;
$this->paginate = array(
'limit' => 10,
'order' => array(
'CompanyRestaurantRequest.id' => 'desc'
)
);
$this->set('requests', $this->paginate("CompanyRestaurantRequest"));
The problem is that I get no CompanyRestaurantRequestFeedResponse.
I tried to attach ContainableBehavior to the CompanyRestaurantRequest model and I used contain key in paginate settings like this:
'contain' => array('CompanyRestaurantRequestFeedResponse');
Anything I try, I can not get those CompanyRestaurantRequestFeedResponses related to CompanyRestaurantRequestFeeds.
How can I make it work?
Thank you!
Intead of lines:
$this->paginate = array(
'limit' => 10,
'order' => array(
'CompanyRestaurantRequest.id' => 'desc'
)
);
At the top of the Controller where all var are declared add:
public $paginate = array(
'CompanyRestaurantRequest' => array(
'limit' => 10,
'order' => array(
'CompanyRestaurantRequest.id' => 'desc'
)
)
);
This should fix it...