I am new to Cakephp and I am having trouble with the following association. What I am after is listing Parts in a table, along with their associated Source vendor. So in the View/index.ctp the table I am currently getting is
ID Source Part #
1 1 Part00001
but I would like the association to display
ID Source Part #
1 Vendor 1 Part00001
where the Source.name is from the mstr_sources db table, not the mstr_parts table.
Below are snippets from all the pertinent code
class MstrPart extends AppModel {
public $name = 'MstrPart';
public $belongsTo = 'MstrSource';
}
class MstrPartsController extends AppController {
public function index() {
$this->set('parts', $this->paginate());
}
}
// <!-- File: /app/View/Users/index.ctp -->
<?php foreach ($parts as $part): ?>
<tr>
<td><?php echo $part['MstrPart']['id']; ?></td>
<td><?php echo $part['MstrPart']['mstr_source_id']['name']; ?></td>
//Also tried the following, still fails
//<td><?php echo $part['MstrPart']['MstrSource']['name']; ?></td>
<td><?php echo $part['MstrPart']['name']; ?></td>
</tr>
// Output of the error message context.
$viewFile = 'C:\Dev\UniServerZ\www\campman\app\View\MstrParts\index.ctp'
$dataForView = array(
'parts' => array(
(int) 0 => array(
'MstrPart' => array(
[maximum depth reached]
),
'MstrSource' => array(
[maximum depth reached]
)
)
)
)
$parts = array(
(int) 0 => array(
'MstrPart' => array(
'id' => '1',
'mstr_source_id' => '1',
'created' => '2013-12-18 16:10:35',
'modified' => '2013-12-18 16:10:35',
'name' => 'Part00001',
'description' => 'Just some basic text, not the real thing.'
),
'MstrSource' => array(
'id' => '1',
'created' => '2013-12-19 12:23:22',
'modified' => '2013-12-19 12:23:22',
'name' => 'Vendor 1'
)
)
)
$part = array(
'MstrPart' => array(
'id' => '1',
'mstr_source_id' => '1',
'created' => '2013-12-18 16:10:35',
'modified' => '2013-12-18 16:10:35',
'name' => 'Part00001',
'description' => 'Just some basic text, not the real thing.'
),
'MstrSource' => array(
'id' => '1',
'created' => '2013-12-19 12:23:22',
'modified' => '2013-12-19 12:23:22',
'name' => 'Vendor 1'
)
)
include - APP\View\MstrParts\index.ctp, line 35
View::_evaluate() - CORE\Cake\View\View.php, line 929
View::_render() - CORE\Cake\View\View.php, line 891
View::render() - CORE\Cake\View\View.php, line 460
Controller::render() - CORE\Cake\Controller\Controller.php, line 952
Dispatcher::_invoke() - CORE\Cake\Routing\Dispatcher.php, line 192
Dispatcher::dispatch() - CORE\Cake\Routing\Dispatcher.php, line 160
[main] - APP\webroot\index.php, line 108
Is there something obvious that I am missing?
I think you would just need to change this line
<td><?php echo $part['MstrPart']['mstr_source_id']['name']; ?></td>
To this
<td><?php echo $part['MstrSource']['name']; ?></td>
EDIT: I'll explain a bit.
In cakephp, all joined models (either joined via the 'join' tag within the Model->find, a containable behavior, or via the default bindings established in the model file) are included in the results array via a key of their model name. *it's their model name, not the table name. See cakephp naming conventions for more.
Since you want the column from mstr_source and not mstr_part, you want to reference the data inside the MstrSource dictionary and not MstrPart
Related
in my project I have database
"Products" hasAndBelongsToMany "Sizes"
"ProductsSize" belongsTo "Products"
"ProductSize" belongsTo "Size"
In ProductsSize, one product_id may have many size_id.
hence, i want to do a form that have a select type input that list down all the size_id where the product_id = $id.
What i have done is:
in controller:
$size = $this->Product->ProductsSize->find('all', array(
'conditions' => array('ProductsSize.product_id' => $id),
'fields' => array('ProductsSize.size_id'),
));
in view:
<?php echo $this->form->create('Cart', array('action' => 'add')); ?>
<?php echo $this->form->input('size_id', array('label' => 'Size', 'options' => $size)); ?>
then i got error: Undefined index: ProductsSize
but when i put foreach, the data shown:
<?php foreach ($size_apparel as $size): ?>
<?php echo $size['ProductsSize']['size_id'];?><br/>
<?php endforeach; ?>
can anyone please help me to do the foreach in options.
The problem is that you are using an invalid array for the options. You are requesting:
$size = $this->Product->ProductsSize->find('all', array(
'conditions' => array('ProductsSize.product_id' => $id),
'fields' => array('ProductsSize.size_id'),
));
What you should be requesting is:
$size = $this->Product->ProductsSize->find('list', array(
'conditions' => array('ProductsSize.product_id' => $id),
));
This will return the options for the form field in the format it expects which is:
array(
{id} => {size},
{id} => {size},
{id} => {size},
{id} => {size},
...
)
I think you meant to say
<?php echo $this->form->input('size_id', array('label' => 'Size', 'options' => $size)); ?>
note 'options' instead of 'value'
$List = Set::classicExtract($size, '{n}.ProductSize.product_id');
$List will contain key value(ProductSize.product_id) pair.
OR you can change your query as
$size = $this->Product->ProductSize->find('list', array(
'conditions' => array('ProductSize.product_id' => $id),
));
Hope it will work for you
I'm trying to set up a commercial proposal system using CakePHP 2.3.
It has 5 tables which are associated (see details below).
This system will have 1 page on which are 5 forms for each table. (see details below).
Form 1: table proposals
Form 2: table clients FK proposal_id
Form 3: table products FK client_id
Form 4: table specifications FK product_id (of the product)
Form 5: table appendices FK product_id (of the product)
WHERE:
proposals hasOne clients.
----------v----------
clients beongsTo proposals AND hasMany products.
----------v----------
products belongsTo clients AND hasMany specifications & appendices.
----------v----------
specifications belongsTo products.
appendices belongsTo products.
The form 4 can have multiple row so it's inside a foreach loop to generate more input. Same for the form 5. Because 1 product can have multiple specifications and appendices.
I admit, it's pretty tricky :)
This is the solution I finally chose, but maybe there is better. For exemple, I could make a multi-step form but it seems quite difficult to put in place. Anyway, i'm open to suggestion.
Meanwhile, I'm sure we can make this work so here are the details. For each table, I have created a model and made the appropriated connections. In each model I have enable the containable behaviour: public $actsAs = array('Containable');.
Now here is the ProposalsController.php:
function admin_edit($id=null){
$this->loadModel('Proposal','Client','Product', 'Specification', 'Appendice');
$this->Proposal->contain('Proposal','Client','Product', 'Specification', 'Appendice');
if ($this->request->is('put') || $this->request->is('Post')) {
$data = $this->request->data;
if (!empty($data)) {
// Use the following to avoid validation errors:
// unset($this->Proposal->Client->validate['proposal_id']);
// $this->Proposal->saveAssociated($data);
// $this->Session->setFlash("Le contenu a bien été édité");
// $this->redirect(array('action' => 'index', $data['Product']['id']));
debug($data);
}
}
elseif($id){
$this->Proposal->id = $id;
$this->request->data = $this->Proposal->read(null,$id);
}
}
This edit action has many errors because I don't know how to set it up correctly in that case. So forgive me but I give you a raw code :). I would like this admin_function to add or edit, but again, in this case I don't know how to handle it.
And the view admin_edit.ctp :
<hr/>
<h1>Proposition</h1>
<hr/>
<?php echo $this->Form->create('Product'); ?>
<?php echo $this->Form->input('Proposal.name', array('label' => "Nom de la proposition")); ?>
<?php echo $this->Form->input('Proposal.created', array('label' => "Date de création")); ?>
<?php echo $this->Form->input('Proposal.due', array('label' => "Date d'échéance")); ?>
<?php echo $this->Form->input('Proposal.content', array('label' => "Termes & conditions")); ?>
<hr/>
<h1>Client</h1>
<hr/>
<?php echo $this->Form->input('Client.name', array('label' => "Nom du client")); ?>
<?php echo $this->Form->input('Client.project', array('label' => "Nom du projet")); ?>
<?php echo $this->Form->input('Client.address', array('label' => "Adresse")); ?>
<?php echo $this->Form->input('Client.phone', array('label' => "Téléphone")); ?>
<?php echo $this->Form->input('Client.email', array('label' => "Email")); ?>
<?php echo $this->Form->hidden('Client.proposal_id'); ?>
<hr/>
<h1>Produit</h1>
<hr/>
<?php echo $this->Form->input('Product.0.name', array('label' => "Nom du produit")); ?>
<?php echo $this->Form->input('Product.0.reference', array('label' => "Référence")); ?>
<?php echo $this->Form->input('Product.0.image', array('label' => "Image")); ?>
<?php echo $this->Form->input('Product.0.pu', array('label' => "Prix Unitaire")); ?>
<?php echo $this->Form->input('Product.0.quantity', array('label' => "Quantité")); ?>
<?php echo $this->Form->input('Product.0.ce', array('label' => "CE")); ?>
<?php echo $this->Form->input('Product.0.nf', array('label' => "NF")); ?>
<?php echo $this->Form->input('Product.0.rohs', array('label' => "RoHS")); ?>
<?php echo $this->Form->hidden('Product.0.client_id'); ?>
<hr/>
<h1>Spécifications :</h1>
<hr/>
<?php
foreach (range(0,1) as $i):
$a=$i+1;
echo '<p>Spécification '.$a.'</p>';
echo $this->Form->input('Specification.'.$i.'.name', array('label' => "Nom de la spécification"));
echo $this->Form->input('Specification.'.$i.'.value', array('label' => "Valeur de la spécification"));
echo $this->Form->hidden('Specification.'.$i.'.product_id');
endforeach;
?>
<hr/>
<h1>Annexes :</h1>
<hr/>
<?php
foreach (range(0,1) as $j):
$b=$j+1;
echo '<p>Annexe '.$b.'</p>';
echo $this->Form->input('Appendice.'.$j.'.name', array('label' => "Image"));
echo $this->Form->input('Appendice.'.$j.'.content', array('label' => "Description de l'annexe"));
echo $this->Form->hidden('Appendice.'.$j.'.product_id');
endforeach;
?>
<?php echo $this->Form->end('valider'); ?>
And finally, here is the array result of the debug($data):
array(
'Proposal' => array(
'name' => 'Proposition 3',
'created' => array(
'month' => '02',
'day' => '19',
'year' => '2013',
'hour' => '08',
'min' => '27',
'meridian' => 'am'
),
'due' => array(
'month' => '02',
'day' => '19',
'year' => '2013',
'hour' => '08',
'min' => '27',
'meridian' => 'am'
),
'content' => 'Termes & conditions'
),
'Client' => array(
'name' => 'Client 3',
'project' => 'Projet Client 3',
'address' => 'Adresse Client 3',
'phone' => 'Téléphone Client 3',
'email' => 'Email#test.com',
'proposal_id' => ''
),
'Product' => array(
(int) 0 => array(
'name' => 'Produit 3',
'reference' => 'Référence Produit 3',
'image' => 'Image Produit 3',
'pu' => '100.77',
'quantity' => '1000',
'ce' => '1',
'nf' => '0',
'rohs' => '0',
'client_id' => ''
)
),
'Specification' => array(
(int) 0 => array(
'name' => 'Specification 1',
'value' => 'Valeur 1',
'product_id' => ''
),
(int) 1 => array(
'name' => 'Specification 2',
'value' => 'Valeur 2',
'product_id' => ''
)
),
'Appendice' => array(
(int) 0 => array(
'name' => 'Image annexe 1',
'content' => 'Description de l'annexe',
'product_id' => ''
),
(int) 1 => array(
'name' => 'Image annexe 2',
'content' => 'Description de l'annexe',
'product_id' => ''
)
)
)
So in this array, everything is there. I just need to take these data and save them all in the corresponding tables. The first problem is to manage with the table's associations. Then the 2 foreach loops that generate multiple row.
I would like to save it all at once but is it even possible?
After trying many ways to get it work, I've gone completely crazy and I just lost myself. I'm really desperate on that one, i mix up everything between the saving method and the request->data that contains everything but cannot get it saved. Anyway, i'm desperately in need for help!
Thank you very much in advance for all the help you can give me, I really appreciate!
[EDIT]
I add my model to the present post for more detail.
Proposal.php:
<?php
class Proposal extends AppModel {
public $actsAs = array('Containable');
public $validate = array(
'name' => array(
'rule' => 'notEmpty',
'message' => "Veuillez préciser un titre"
)
) ;
public $hasOne = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'proposal_id',
'dependent' => true
)
);
}
Client.php:
<?php
class Client extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'Proposal' => array(
'className' => 'Proposal',
'foreignKey' => 'proposal_id'
)
);
public $hasMany = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'client_id',
'conditions' => '',
'order' => '',
'limit' => '',
'dependent' => true
)
);
}
Product.php:
<?php
class Product extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
public $hasMany = array(
'Specification' => array(
'className' => 'Specification',
'foreignKey' => 'product_id',
'conditions' => '',
'order' => '',
'limit' => '',
'dependent' => true
),
'Appendice' => array(
'className' => 'Appendice',
'foreignKey' => 'product_id',
'conditions' => '',
'order' => '',
'limit' => '',
'dependent' => true
)
);
}
Specification.php:
<?php
class Specification extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id'
)
);
}
Appendice.php:
<?php
class Appendice extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'ProductAppend' => array(
'className' => 'Product',
'foreignKey' => 'product_id'
)
);
}
What's the output when you save the data?
if (!empty($this->data)) {
$this->Proposal->save($this->data);
}
You should also check the sql-output
echo $this->element('sql_dump');
edit:
Well after your edit, on the first look it seems that your relations are wrong.
Check out the examples in the book: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
For example hasOne: the other model contains the foreign key.
As I said earlier, you should try to start with just one relation, getting it to work. Afterwords, it'll be much easier to get the other working. So try to comment-out everything except your Proposal and Client model. Then try saving just those two.
I am using contain behavior and i want to be able to sort the data as always but I am having troubles.
It might be because the columns i want to sort are not columns on the paginate table but on the contain tables.
Subscriptions table only contains the "user_id" and the "post_id".
At the controller i have:
$this->paginate = array(
'conditions' => array('Subscription.user_id' => $this->Session->read('Auth.User.id')),
'paramType' => 'querystring',
'limit' => 20,
'contain'=> array('User', 'Post' => array('Priority', 'Status'))
);
$this->set('subscriptions', $this->paginate('Subscription'));
And in my view, this:
<!-- example of not working sort -->
<th class="td_subject"><?php echo $this->Paginator->sort('subject'); ?></th>
The data of subject, for example, is contained on the array $subscription with the normal format:
$subscription['Post']['subject']
And i print it this way:
foreach ($subscriptions as $subscription):
echo ...
echo '<td>'.h($subscription['Post']['subject'].'</td>';
echo ...
endforeach;
How can i use pagination in this case? Thanks.
Don't use contain in this case, manually join the tables:
$this->paginate = array(
'conditions' => array('Subscription.user_id' => $this->Session->read('Auth.User.id')),
'paramType' => 'querystring',
'limit' => 20,
'joins'=>array(
array(
'table'=>'users',
'alias'=>'User',
'conditions'=>array(
'Subscription.user_id = User.id
)
),
array(
'table'=>'posts',
...
),
array(
'table'=>'priorities',
...
),
array(
'table'=>'status',
...
)
)
);
Your view:
<?php echo $this->Paginator->sort('Post.subject', 'Subject'); ?>
When creating a view I am getting a undefined index error: Account on the line with $senderName['Account']['company_name']but when debugging the variable the array prints out
array(
(int) 0 => array(
'Account' => array(
'id' => '0',
'street' => 'SYSTEM',
'city' => 'SYSTEM',
'postcode' => '0',
'state' => 'SYS',
'country' => 'SYS',
'active' => true,
'company_name' => 'SYSTEM',
'abn' => '0'
),
'Template' => array(),
'User' => array(),
'Invoice' => array()
),
here is the code for my view
<?php foreach($invoice as $invoices):?>
<?php foreach($senderName as $senderName):?>
<?php foreach($receiverName as $receiverName):?>
<tr>
<tr>
<td align='center'><?php echo $senderName['Account']['company_name']; ?></td>
<td align='center'><?php echo $receiverName['Account']['company_name']; ?></td>
<td align='center'><?php echo $this->Form->Html->link($invoices['Invoice']['id'],
array('controller' => 'Invoices','action'=>'viewinvoice',$invoices['Invoice']['id'])); ?></td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php endforeach; ?>
and just in case here is my related function
$accounts2=$this->User->find('list', array(
'fields'=>array('account_id'),
'conditions' => array(
'id' => $this->Auth->user('id'))));
$invoices=$this->Invoice->find('all', array(
'conditions' => array(
'Invoice.receiver_id' => $accounts2)));
$sender=$this->Invoice->Find('list', array('fields'=>('sender_id')));
$receiver=$this->Invoice->Find('list', array('fields'=>('receiver_id')));
$senderName=$this->Account->Find('all', array(
'conditions' => array(
'id'=>array_values($sender))));
$receiverName=$this->Account->find('all', array(
'conditions' => array(
'id'=>array_values($receiver))));
debug($senderName);
$this->set('senderName', $senderName);
$this->set('accounts2', $accounts2);
$this->set('receiverName', $receiverName);
$this->set('sender',$sender);
$this->set('receiver',$receiver);
$this->set('invoice', $invoices);
}
You're computer is right. :)
$senderName['Account']['company_name']
does not exists.
$senderName['0']['Account']['company_name']
does.
The data comes in this format as they may be several account liked to senderName.
Edit:
Could you give the relationship in your models too?
I think you should review your code in view :
<?php foreach($senderName as $senderName):?>
<?php foreach($receiverName as $receiverName):?>
in foreach array_expression and value variable should be different but you have used same variable name, please use different names for this.
I'm struggling to find the answer to this. I have only been using CakePHP for a month and I've hit a problem. It's something I can fix by manually inserting the values but I expected my data to pre-populate. Here is what is happening:
The Model is Product which hasMany 'Dynamicprice'
I'm testing a product with the id of 7 (/products/edit/7).
the first part of my edit function is:
public function edit($id = null) {
$this->Product->id = $id;
if (!$this->Product->exists()) {
throw new NotFoundException('Invalid Product');
}
if ($this->request->is('get')){
$this->request->data = $this->Product->read();
}
debug($this->request->data);
//other stuff setting vars for drop-down lists
}
the
debug($this->request->data);
gives me the following:
array(
'Product' => array(
'id' => '7',
'category_id' => '70',
'name' => 'Full Test',
'description' => 'This is to test all features',
'price' => '0.00',
'aesthetic' => true,
'image' => '',
'price_structure' => '2',
'suggest_for' => '',
'created' => '2012-06-28 12:49:06',
'modified' => '2012-06-28 12:49:06'
),
'Dynamicprice' => array(
(int) 0 => array(
'id' => '15',
'product_id' => '7',
'drop' => '600',
'prices' => '6000:9.99, 12000:18.99 '
),
(int) 1 => array(
'id' => '16',
'product_id' => '7',
'drop' => '1200',
'prices' => '6000:19.99, 12000:28.99 '
),
(int) 2 => array(
'id' => '17',
'product_id' => '7',
'drop' => '2400',
'prices' => '6000:29.99, 12000:38.99 '
)
)
)
However, whilst everything in ['Product'] pre-populates the ['Dynamicprice'] array does not pre-populate the following:
<?php
echo $this->Form->input('Dynamicprices.0.id');
echo $this->Form->input('Dynamicprices.0.drop', array('label' => 'Drop 1 (mm). Enter "0" for "Any Drop"'));
echo $this->Form->input('Dynamicprices.0.prices', array('label' => 'Prices 1', 'type' => 'textarea', 'rel' => 'dynamic'));
?><hr><?php
echo $this->Form->input('Dynamicprices.1.id');
echo $this->Form->input('Dynamicprices.1.drop', array('label' => 'Drop 2 (mm).'));
echo $this->Form->input('Dynamicprices.1.prices', array('label' => 'Prices 2', 'type' => 'textarea', 'rel' => 'dynamic'));
?><hr><?php
echo $this->Form->input('Dynamicprices.1.id');
echo $this->Form->input('Dynamicprices.2.drop', array('label' => 'Drop 3 (mm).'));
echo $this->Form->input('Dynamicprices.2.prices', array('label' => 'Prices 3', 'type' => 'textarea', 'rel' => 'dynamic'));
?>
Am I right to expect them to populate automatically and if so what have I done wrong?
I have created /Model/Dynamicprice.php with the following just to make sure:
class Dynamicprice extends AppModel {
public $name = 'Dynamicprice';
public $belongsTo = 'Product';
But as I expected it didn't change anything.
This is the second time I've done this this week; ask a stupid question. Yes I was right to expect them to pre-populate. The problem is I got my naming conventions mixed up. "Dynamicprices.1.drop" shouldn't have the 's' at the end. Silly me!