CakePHP Validation Issue for dynamic fields - cakephp

I have created below fields in my form-
<input type="text" id="ProductPrice1" class="small" name="data[Product][price][1]">
<input type="text" id="ProductPrice1" class="small" name="data[Product][price][2]">
<input type="text" id="ProductPrice1" class="small" name="data[Product][price][3]">
<input type="text" id="ProductPrice1" class="small" name="data[Product][price][4]">
Now I am trying to add validation for above fields by using below model function-
public function productValidates() {
$validate= array();
$validate = array(
'name'=> array(
'mustNotEmpty'=>array(
'rule' => 'notEmpty',
'message'=> __('PRODUCTS.TITLE_BLANK_ERROR',true)
)
),
'description'=> array(
'mustNotEmpty'=>array(
'rule' => 'notEmpty',
'message'=> __('PRODUCTS.DESCRIPTION_BLANK_ERROR',true)
)
),
'category_id'=> array(
'mustNotEmpty'=>array(
'rule' => 'notEmpty',
'message'=> __('PRODUCTS.SELECT_CATEGORY_ERROR',true)
)
),
);
$count = $this->data[$this->name]['total_prices'];
for($i=1; $i<= $count;$i++){
$validate['price'][$i] = array(
'1' => array(
'rule' => array('notEmpty',true),
'message' => __('PRODUCTS.PRICE_EMPTY_ERROR',true),
'last' => true
)
);
}
$this->validate = $validate;
return $this->validates();
}
But its not working.
Can you please suggest what’s the issue here?

I suppose that you are using cakephp 2.X
I think that the problem is the loop, instead of that add a custom validation method to check that the prices are not empty.
Here is the link to the book with an example.
http://book.cakephp.org/2.0/en/models/data-validation.html#adding-your-own-validation-methods
Another solution is to make a table Prices with columns id|product_id|value, put the association in the Models, put the validation criteria of the prices into the Price Model and in the ProductController put "saveAll" instead of save.
In this case your form must be like:
<input type="text" id="ProductName" class="small" name="data[Product][name]">
<input type="text" id="ProductDescription" class="small" name="data[Product][description]">
<input type="text" id="PriceValue1" class="small" name="data[Price][0][value]">
<input type="text" id="PriceValue1" class="small" name="data[Price][1][value]">
<input type="text" id="PriceValue1" class="small" name="data[Price][2][value]">
<input type="text" id="PriceValue1" class="small" name="data[Price][3][value]">
if this does not answer your question I will need more data such as the controller and the structure of your db

Related

CakePHP 2 output checkbox array inside loop

I've read CakePHP multiple checkbox array HTML the right way but getting strange results. I have a list of tags (from a Model called Tag). I want to loop through these and output checkboxes for them in a View.
So I have obtained the Tag data in my Controller with:
$tags = $this->Tag->find('list', ['order' => ['name' => 'ASC']]);
$this->set('tags',$tags);
When I loop through it in my View I am trying to output the checkboxes in between Bootstrap markup:
<?php echo $this->Form->create('GroupTag'); ?>
<?php foreach ($tags as $tag_id => $tag): ?>
<div class="checkbox">
<label>
<?php echo $this->Form->checkbox('tag_id[]', array( 'value'=> $tag_id)); ?>
<?php echo $tag; ?>
</label>
</div>
<?php endforeach; ?>
I copied the syntax for tag_id[] from the post I linked to.
But when I inspect the markup it's producing the following as the name attribute for each <input type="checkbox">:
data[GroupTag][tag_id[]]
Should this not be
data[GroupTag][tag_id][]
?
The idea is that I have multiple checkboxes with a name attribute tag_id[] and then in the Controller I can loop through what has been checked.
Please can someone advise on this as I can't get it working and have looked into examples provided on here/docs.
Try this
$this->Form->checkbox('tag_id.', array( 'value'=> $tag_id))
You can also do this:
$this->Form->input('GroupTag.tag_id', [
'type' => 'select',
'multiple' => 'checkbox',
'options' => $tag_id
]);
FormHelper::select(string $fieldName, array $options, array $attributes)
Example:
$options = array(
'Value 1' => 'Label 1',
'Value 2' => 'Label 2'
);
echo $this->Form->select('Model.field', $options, array(
'multiple' => 'checkbox'
));
Output:
<div class="input select">
<label for="ModelField">Field</label>
<input name="data[Model][field]" value="" id="ModelField"
type="hidden">
<div class="checkbox">
<input name="data[Model][field][]" value="Value 1"
id="ModelField1" type="checkbox">
<label for="ModelField1">Label 1</label>
</div>
<div class="checkbox">
<input name="data[Model][field][]" value="Value 2"
id="ModelField2" type="checkbox">
<label for="ModelField2">Label 2</label>
</div>
</div>

CakePHP 3.4 use setTemplates() multiple times

I'm trying to use setTemplates() multiple times in a view, but it doesn't work as expected.
I have two templates which I want to set when I need them.
$bootstrapTemplate = [
'inputContainer' => '<div class="form-group {{type}}{{required}}">{{content}}</div>',
];
$bootstrapTemplateInputGroup = [
'inputContainer' => '<div class="form-group {{type}}{{required}}">{{content}}</div>',
'input' => '<div class="input-group"><div class="input-group-addon">€</div><input type="{{type}}" name="{{name}}"{{attrs}}/></div>'
];
I start to set the templates like this
$this->Form->setTemplates($bootstrapTemplate);
$this->Form->control('title', ['class' => 'form-control', 'label' => __('Titel')]);
// OUTPUT - correct
// <div class="form-group text required"><label for="title">Titel</label><input type="text" name="title" class="form-control" required="required" maxlength="255" id="title"></div>
$this->Form->setTemplates($bootstrapTemplateInputGroup);
echo $this->Form->control('price', ['class' => 'form-control', 'id' => 'price_eur', 'label' => __('Preis EUR')]).'</div>';
// OUTPUT - correct
<div class="form-group number required"><label for="price_eur">Preis EUR</label><div class="input-group"><div class="input-group-addon">€</div><input type="number" name="price" class="form-control" id="price_eur" required="required" step="any"></div></div>
Now I want to switch back to $bootstrapTemplate which doesn't seem to work. Instead the $bootstrapTemplateInputGroup is used
$this->Form->setTemplates($bootstrapTemplate);
echo $this->Form->control('user_zip', ['class' => 'form-control', 'id' => 'user_zip', 'label' => __('PLZ')])
// OUTPUT - wrong
<div class="form-group text"><label for="user_zip">PLZ</label><div class="input-group"><div class="input-group-addon">€</div><input type="text" name="user_zip" class="form-control" id="user_zip"></div></div>
My expected output is the template of $bootstrapTemplate like:
<div class="form-group text required"><label for="user_zip">PLZ</label><input type="text" name="user_zip" class="form-control" required="required" maxlength="255" id="user_zip"></div>
What am I doing wrong here?
FormHelper::setTemplates() doesn't overwrite the complete existing set of templates, it merges it with the given templates, ie the input template set with the second call, will remain changed.
You either have to push() to (store) and pop() from (restore) the template stack using the underlying templater to avoid that:
$this->Form->templater()->push();
$this->Form->templater()->add($bootstrapTemplateInputGroup);
$this->Form->templater()->pop();
or use the FormHelper::create() method's templates option to apply the templates to the specific FormHelper::control() call(s) only:
echo $this->Form->control('title', ['templates' => $bootstrapTemplate, /*...*/]);
echo $this->Form->control('price', ['templates' => $bootstrapTemplateInputGroup, /*...*/]);
echo $this->Form->control('user_zip', ['templates' => $bootstrapTemplate, /*...*/]);
See also
Cookbook > Views > Helper > Form > Options for Control
API > \Cake\View\StringTemplate

Multiple file upload in custom form with managed_file

I'm building a custom settings form in Drupal 7, with an image upload field. This image field should allow multiple uploads.
After some research I found out you can do this with managed_file and '#attributes' => array('multiple' => 'multiple'). However this doesn't seem to do anything.
This is the code I currently have:
$form['frontpage_banner_images'] = array(
'#type' => 'managed_file',
'#title' => t('Frontpage Images'),
'#name' => 'files[]',
'#attributes' => array(
'multiple' => 'multiple',
'class' => 'testclass',
),
'#upload_location' => 'public://homepage-banners/',
'#default_value' => variable_get('frontpage_banner_images'),
);
With this as result:
<div class="form-item form-type-managed-file form-item-files-">
<label for="edit-frontpage-banner-images-upload">Frontpage Images</label>
<div id="edit-frontpage-banner-images-upload" class="testclass form-managed-file">
<input type="file" id="edit-frontpage-banner-images-upload" name="files[frontpage_banner_images]" size="22" class="form-file">
<input type="submit" id="edit-frontpage-banner-images-upload-button" name="frontpage_banner_images_upload_button" value="Upload" class="form-submit ajax-processed">
<input type="hidden" name="frontpage_banner_images[fid]" value="0">
</div>
</div>
As you can see, the testclass from my #attributes is being applied on the wrapping div and not on the file input. So the multiple attribute isn't doing anything.
This is what I'm trying to achieve (Photoshopped):
Any help on how to achieve this is appreciated.
The multiple option does not seem to be supported. Then again you are using it under the #attributes. This would cause IMO the html element to have an atttribute multiple, but I don't see anything in /modules/file/file.js to pick up on that, so that's presumably why it's not doing anything.
You're probably better off using plupload, as suggested here.

Chaging the label position for an input at CakePHP 2.2

CakePHP usually place labels before the input, so doing this:
echo $this->Form->input('subject');
We obtain this:
<div class="input text required">
<label for="TicketSubject">Subject</label>
<input name="data[Ticket][subject]" maxlength="255" type="text" id="TicketSubject">
</div>
Is there any way to place the label after the input to obtain this?
<div class="input text required">
<input name="data[Ticket][subject]" maxlength="255" type="text" id="TicketSubject">
<label for="TicketSubject">Subject</label>
</div>
Thanks.
The proper way is using the the 'format' option.
$this->Form->input('subject', array(
'format' => array('before', 'input', 'between', 'label', 'after', 'error')
));
Didn't anyone read the API :)
You can try this:
echo $this->Form->input('subject', array('label' => false, 'after' => $this->Form->label('Subject:')));
You can do like this also -
echo $this->Form->input('subject', array('label' => false, 'after' => '<label for="subject">Subject</label>'));

How to format an array using PHP?

I am trying to get the data from the form I created where I used an array to name them like:
<input type="text" name="fname[]" />
<input type="text" name="mname[]" />
<input type="text" name="lname[]" />
where the said form field are dynamically inserted or removed in the page.
On my script to get the values of the forms, I wrote something like:
$student = array(
'fname' => '$_POST[fname]',
'mname' => '$_POST[mname]',
'lname' => '$_POST[lname]',
);
But when I used var_dump to see the values, each field will be indexed from zero and if it has repeating fields, it would be again be declared as another array inside an array.
What I wanted to do is to have an array with this stucture:
$student = array(
array(
'fname' => 'fname1',
'mname' => 'mname1',
'lname' => 'lname1'
),
array(
'fname' => 'fname2',
'mname' => 'mname3',
'lname' => 'lname2'
)
);
I tried using a loop but I just fail again and again. Can anyone help me solve this problem?
Thank you in advance for your help.
<input type="text" name="student[]['fname']" />
<input type="text" name="student[]['mname']" />
<input type="text" name="student[]['lname']" />
no loops necessary. Your $_POST['student'] variable will automatically be the array you wanted to achieve.
EDIT: this isn't achieving the desired result. It's incrementing student for each field. adding an n value to the first set of brackets like student[n][fname] does achieve the desired result. I don't know how the script is written to dynamically generate these three fields on the fly, but if you can figure out how to add an n value you're golden.
<?php
for($i=0; $i<count($_POST['fname']); $i++) {
$student[] = array(
'fname' => $_POST['fname'][$i],
'mname' => $_POST['mname'][$i],
'lname' => $_POST['lname'][$i],
);
}
?>
Oops, I thought Stephan's answer would suffice, but rather, it should be the following I believe (can't test right now). Try it:
<input type="text" name="student[0]['fname']" />
<input type="text" name="student[0]['mname']" />
<input type="text" name="student[0]['lname']" />
<input type="text" name="student[1]['fname']" />
<input type="text" name="student[1]['mname']" />
<input type="text" name="student[1]['lname']" />
etc...
(note the added numeric indexes)
Then when you do a echo '<pre>' . print_r( $_POST[ 'student' ], true ); you should see the structure you are looking for.

Resources