cakePHP bind hasmany through relationship - php

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);

Related

Data Provider relation not getting required data

Guardian model:(relation)
'studentsGuardians' => array(self::HAS_MANY, 'StudentsGuardian', 'guardian_id'),
Student model relation:
'studentsGuardians' => array(self::HAS_MANY, 'StudentsGuardian', 'student_id'),
Students Guardian model relation:
'guardian' => array(self::BELONGS_TO, 'Guardian', 'guardian_id'),
'student' => array(self::BELONGS_TO, 'Student', 'student_id'),
Now in controller i want to select those students whose guardian_id=id but my code select all records without filtering. my code is
public function actionAssignGuardian($id)
{
$dataProvider = new CActiveDataProvider('Student',
array(
'criteria' => array(
'with'=>array('studentsGuardians',
array('criteria'=>
array('with'=>array('guardian','condition'=>' guardian_id=:id',
'params'=>array('id'=>$id))))),
),
));
$this->renderPartial('Pages/_assignGuardian', array(
'dataProvider' => $dataProvider,
'id'=>$id,
));
}
Kindly point me to correct way that how could i select those students whose guardian_id= given id in function. I am new to yii.
Thanks.
Add this line into Student model (below previous relation line studentsGuardians)
'guardians' => array(self::HAS_MANY, 'Guardian', array('guardian_id'=>'guardian_id'),'through'=>'studentsGuardians'),
Then you can do query like this
$dataProvider = new CActiveDataProvider('Student',
array(
'criteria' => array(
'with'=>array(
'guardians' =>array(
'condition'=>' guardian_id=:id',
'params'=>array('id'=>$id)
)))
));
(You should also dump $id to make sure that it is valid value)

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 - Correct way to do hasMany through

I have 3 models
Categories:
class Category extends AppModel {
public $belongsTo = array(
'Parent' => array(
'className' => 'Category',
'foreignKey' => 'parent_id'
),
);
public $hasMany = array(
'Children' => array(
'className' => 'Category',
'foreignKey' => 'parent_id'
),
'UserCategoryMeta'
);
}
Users:
class User extends AppModel {
public $hasMany = array(
'UserCategoryMeta' => array(
'className' => 'UserCategoryMeta',
'foreignKey' => 'user_id',
),
);
}
UserCategoryMeta:
class UserCategoryMeta extends AppModel
{
public $belongsTo = array(
'User', 'Category'
);
}
What I need to do is have each user be able to choose many categories and for each of those associations I need the user to set search terms which is just 1 field in the DB.
So the UserCategoryMeta table looks like this:
id | user_id | category_id | search_terms
I've found a way which might work but it seems very hacky.
In the usercontroller I have:
$Categories = $this->User->Category->find('list');
Then in the add view I have the checkboxes:
echo $this->Form->input('Category.Category',array(
'type' => 'select',
'multiple' =>'checkbox',
'options' => $Categories,
));
Then the only way I could get each of those checkboxes to have a search terms input next to them is to do this in the add view:
foreach ($Categories as $key => $category){
echo '<input type="text" id="Category'.$key.'SearchTerms" name="data[Category][search_terms]['.$key.']"><br/>';
}
This produces what I want but obviously since I'm just creating random inputs when the form get's submitted it get's black holed. I have managed to get passed this but I know I'm doing it the wrong way and hopefully someone can help me do it the right way.
Also then once I have this data array in the controller im not sure how to save it to the database correctly.
Thanks in advance for any help!
Just do what you're doing, but in the repeat, use $this->Form->input instead of just manually writing the HTML.

cakephp HABTM same model

I have a site develop in cakephp 2.0
I want to make a HABTM relation to the same model: A product can has more products.
I thinked to do in this mode into my model:
class Product extends AppModel {
public $name = 'Product';
public $useTable = 'products';
public $belongsTo = 'User';
public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Ingredient' => array(
'className' => 'Product',
'joinTable' => 'ingredients_products',
'foreignKey' => 'product_id',
'associationForeignKey' => 'ingredient_id',
'unique' => true
)
);
}
Is correct my relation? But have I to insert into my table products the field product_id and ingredient_id?
And how can I save my data with a form? I know how to save data with HABTM but I never done an HABTM to the same table.
Your relation is fine. What you have written will create a Product Model that can have any number of Ingredients and allows an Ingredient to belong to any number of Products.
When saving, you must simply treat the Ingredient as if it were another Model. The CakePHP example on saving HABTM works just as well as for associating the same model as with 2 different models: http://book.cakephp.org/2.0/en/models/saving-your-data.html.
So, if you're saving multiple Ingredients to a Product, your Array structure will look like this:
Array(
[0] => Array(
Product => Array(
id => 1
),
Ingredient => Array(
id => 18
)
),
1 => Array(
Product => Array(
id => 1
),
Ingredient => Array(
id => 23
)
)
// ...
)
It is up to you how you capture this in a form, but the form example used in the link provided above should manage this properly.

cakephp HABTM save null field

I have a site develop in cakephp 2.0.
I have a relation HABTM to the same model like this:
class Product extends AppModel {
public $name = 'Product';
public $useTable = 'products';
public $belongsTo = 'User';
public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'ingredients_products',
'foreignKey' => 'product_id',
'associationForeignKey' => 'ingredient_id',
'unique' => false
)
);
}
I want to save a record into my view with a simple form like this:
echo $this->Form->create('IngredientProduct', array ('class' => 'form', 'type' => 'file'));
foreach ($product as $prod) {
echo '<div>'.$prod['ProductAlias']['alias'].'</div>';
echo $this->Form->input('IngredientProduct.product_id', array ('type'=>'text', 'value'=> $prod['ProductAlias']['id'], 'label'=> false, 'id' => 'id'));
}
$select = '<select name="data[IngredientProduct][ingredient_id]" id="[IngredientProductIngredientId">';
foreach ($other_product as $prod2) {
$select .= '<option value="'.$prod2['ProductAlias']['id'].'">'.$prod2['ProductAlias']['alias'].'</option>';
}
$select .= '</select><br>';
echo($select);
echo $this->Form->submit('Collega', array('id'=>'link_product'));
echo $this->Form->end();
Into my controller I save in this mode:
if ($this->Product->saveAll($this->request->data)){
$this->Session->write('flash_element','success');
$this->Session->setFlash ('Prodotto collegato con successo.');
//$this->redirect(array('action'=>'edit',$alias));
}
else{
$this->Session->write('flash_element','error');
$this->Session->setFlash('Errore di salvataggio activity');
}
When I'm going to see into the database I see that ingredient:id is setting well but product_id is 0.
I have debugged my request->data and this is the array:
array(
'IngredientProduct' => array(
'product_id' => '1',
'ingredient_id' => '2'
)
)
I have print the sql query created by cakephp:
INSERT INTO `db`.`ingredients_products` (`product_id`, `ingredient_id`, `modified`, `created`) VALUES ('', 2, '2012-10-09 23:19:22', '2012-10-09 23:19:22')
Why product_id is null instead of 1?
Can someone help me?
Thanks
I think this line is wrong:
$this->Product->saveAll($this->request->data);
Try:
$this->IngredientProduct->saveAll($this->request->data);
as your form seems to ask data for a relationship, not a new product.

Categories