Creating 'select' listboxes using FormHelper in CakePHP - cakephp

I have two models, Category and Point. The associations are defined as:
Category hasMany Point
Point belongsTo Category
I would like, when adding Points to my database, to be able to select the category it belongs to from a <select> box, along with the rest of the form data.
Where would I need to set the category list and how could I do it? And how would I produce the select box?
I assume it could be done with
$form->input('categorieslist',array('type'=>'select')); //categorieslist needs
//setting somewhere.

Also to generalize a bit:
In a View with access to the Form helper
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'key1' => 'val1',
'key2' => 'val2',
),
));
?>
The above will render a select input with two options. You can also place an empty option as the first item. Passing a value of true will simply append an empty option with a blank value to the beginning of the options rendered in the HTML.
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'key1' => 'val1',
'key2' => 'val2',
),
'empty' => true,
));
?>
You can pass a string to the 'empty' key to have it display custom text as the key field for the empty option.
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'California' => 'CA',
'Oregon' => 'OR',
),
'empty' => 'choose a state',
));
?>
One last example, you can also pre-select an option with the selected key. The value should match the value of one of the select options, not the key.
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'California' => 'CA',
'Oregon' => 'OR',
),
'empty' => 'choose a state',
'selected' => 'California',
));
?>
From the Model
Model->find( 'list', array( ... )); will always return an array formatted for use with select box options. If you pass data to your view stored in a variable with a lowercase plural model name, that is, ( $this->set( 'categories', $categories );, then you will automagically generate drop downs for related models by using the form helper in the view and passing it a data index of the same model name in singular form suffixed with "_id".
Aziz's answer at #2 is the example of that automagic kicking in.
CakePHP 1.3 Form Helper
CakePHP1.2 Form Helper

In the controller:
$categories = $this->Point->Category->find('list');
$this->set(compact('categories'));
In the view:
$form->input('category_id',array('type'=>'select'));

Related

CakePHP2 - Default value for input - select with option multiple

I have Form input with multiple select options. I am unable to set default values. This is my code:
<?= $this->Form->input('PaymentMethods', array(
'type' => 'select',
'multiple' => true,
'label' => false,
'options' => array(
'cash'=>'cash',
'invoice'=>'invoice',
'ax'=>'ax',
'ca'=>'ca',
'vi'=>'vi',
'tp'=>'tp',
'dc'=>'dc'
),
'default'=>'ax'
)); ?>
How do I set default values for this input with PHP only?
This is working on my system. You can also set it from controller like this :
$this->request->data[$this->modelClass]['PaymentMethods'] = 'ax';
Please check these url also
CakePHP select default value in SELECT input
http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html
example :
$sizes = array('s' => 'Small', 'm' => 'Medium', 'l' => 'Large');
echo $this->Form->input(
'size',
array('options' => $sizes, 'default' => 'm')
);
Since this is multi-choice select, value given must be array. And the key shouldn't be default, I should've used value instead.
<?= $this->Form->input('PaymentMethods', array(
'type' => 'select',
'multiple' => true,
'label' => false,
'options' => $options,
'value'=> $array_of_data_fetched_from_database
)); ?>

How to properly pass multiple lists from controller to view?

This is my simplified problem description. I have several tables with similar columns which contain different data:
table_one.id, table_one.name, ..., table_one.foo
table_two.id, table_two.name, ..., table_two.foo
table_one.foo allowed values are 'a', 'b', 'c',
table_two.foo allowed values are 'x', 'y', 'z'.
In the view I have a form that allows to enter several records into table_one and table_two:
$this->Form->input('TableOne.0.foo', array('type' => 'select'));
$this->Form->input('TableOne.1.foo', array('type' => 'select'));
$this->Form->input('TableOne.2.foo', array('type' => 'select'));
...
$this->Form->input('TableTwo.0.foo', array('type' => 'select'));
$this->Form->input('TableTwo.1.foo', array('type' => 'select'));
$this->Form->input('TableTwo.2.foo', array('type' => 'select'));
In the controller I construct the lists and pass them to the view:
$tableOneFooList = array('a', 'b', 'c');
$tableTwoFooList = array('x', 'y', 'z');
$this->set('foo', $tableOneFooList);
The problem with that is that I cannot set the second foo variable and $tableOneFooList is populated into all 6 select boxes. I could name the lists differently in the controller but that would require more work in the view to select the right values after a failed validation. Is there a good way to pass the lists to the view so that if the form doesn't validate after the submission the selected values would be preserved? Maybe I do not know some naming convention?
As far as I know the form helper magic isn't able to distinguish such two fields, you'll either have to pass the lists separately, or use a custom form helper.
Using the options option
When passing the lists separately, all you have to do is using the options option, if necessary CakePHP will automatically select the appropriate list entries based on the values passed in the request.
Controller
$tableOneFoos = array('a', 'b', 'c');
$tableTwoFoos = array('x', 'y', 'z');
$this->set(compact('tableOneFoos', 'tableTwoFoos'));
View
$this->Form->input('TableOne.0.foo', array('type' => 'select', 'options' => $tableOneFoos));
$this->Form->input('TableOne.1.foo', array('type' => 'select', 'options' => $tableOneFoos));
$this->Form->input('TableOne.2.foo', array('type' => 'select', 'options' => $tableOneFoos));
$this->Form->input('TableTwo.0.foo', array('type' => 'select', 'options' => $tableTwoFoos));
$this->Form->input('TableTwo.1.foo', array('type' => 'select', 'options' => $tableTwoFoos));
$this->Form->input('TableTwo.2.foo', array('type' => 'select', 'options' => $tableTwoFoos));
That's it, the values should be selected as expected when rendering the form with the submitted data.
Custom form helper
The form helper checks for variable names that are camelCased plurals of the fieldname (see FormHelper::_optionsOptions()), the model name isn't taken into account, and so in your case it will look for foos, and that's why you end with this one list being used for all inputs.
You can override that method and implement an additional check that uses the model name, so that the helper would look for variables like tableOneFoos and tableTwoFoos.
Here's an untested! example:
App::uses('FormHelper', 'View/Helper');
class MyFormHelper extends FormHelper {
protected function _optionsOptions($options) {
$options = parent::_optionsOptions($options);
if (!isset($options['options'])) {
// this is where the magic happens, an entity name like
// `Model_field` is turned into a variable name like
// `modelFields` which is then used to lookup the view vars.
$entityName = $this->model() . '_' . $this->field();
$varName = Inflector::variable(
Inflector::pluralize(preg_replace('/_id$/', '', $entityName))
);
$varOptions = $this->_View->get($varName);
if (is_array($varOptions)) {
if ($options['type'] !== 'radio') {
$options['type'] = 'select';
}
$options['options'] = $varOptions;
}
}
return $options;
}
}
Then you could just pass tableOneFoos and tableTwoFoos to the view without using the options and type options for the inputs:
Controller
$tableOneFoos = array('a', 'b', 'c');
$tableTwoFoos = array('x', 'y', 'z');
$this->set(compact('tableOneFoos', 'tableTwoFoos'));
View
$this->MyForm->input('TableOne.0.foo');
$this->MyForm->input('TableOne.1.foo');
$this->MyForm->input('TableOne.2.foo');
$this->MyForm->input('TableTwo.0.foo');
$this->MyForm->input('TableTwo.1.foo');
$this->MyForm->input('TableTwo.2.foo');
This should work as long as there are no TableOneFoo or TableTwoFoo models used in a HABTM fashion way, as their fields would end up with the same variable names, ie tableOneFoos and tableTwoFoos.
Lets not make this complex-- Simple solution would be-
<?php
$tableOneFooList = array('a', 'b', 'c');
$tableTwoFooList = array('x', 'y', 'z');
echo $this->Form->create();
echo $this->Form->input('TableOne.0.foo', array('type' => 'select', 'options' => $tableOneFooList));
echo $this->Form->input('TableOne.1.foo', array('type' => 'select', 'options' => $tableOneFooList));
echo $this->Form->input('TableOne.2.foo', array('type' => 'select', 'options' => $tableOneFooList));
echo $this->Form->input('TableTwo.0.foo', array('type' => 'select', 'options' => $tableTwoFooList));
echo $this->Form->input('TableTwo.1.foo', array('type' => 'select', 'options' => $tableTwoFooList));
echo $this->Form->input('TableTwo.2.foo', array('type' => 'select', 'options' => $tableTwoFooList));
echo $this->Form->end('Submit');
?>

cakephp How can I convert passed params to named params to prefill element form?

I'm using CakePHP version 2.2.3 I have an element with a search box and a few dropdowns that use CakeDC's search plugin. It works great and just passes the selected/searched items in the URL like this www.mydomain.com/products/cid:1/mid:3/terms:these%20terms where cid is category id, and mid is manufacturer id.
I created pages that allow you to click a category to find all products in that category, but I can't get the category select box, in the element, to select the category of the page it is on. It works if I use the same URL structure as my element submits but I want a clean URL for SEO so I setup the following custom route:
/**
* Categories
*/
Router::connect(
'/products/category/:cid-:slug', // E.g. /products/category/3-my_category
array('controller' => 'products', 'action' => 'category'),
array(
'pass' => array('cid', 'slug'),
'cid' => '[0-9]+'
)
);
this results in a nice looking URL but doesn't pre-select the value of my select list.
I was able to get it working with the code below in my element, but it seems "hacky/clunky"
if(isset($this->params['named']['cid']) && !empty($this->params['named']['cid'])){
echo $this->Form->input('cid', array('label' => false, 'default' => $this->params['named']['cid'], 'options' => $categories, 'empty' => ' ( Category ) '));
}elseif(isset($this->params['pass']['0']) && !empty($this->params['pass']['0'])){
echo $this->Form->input('cid', array('label' => false, 'default' => $this->params['pass']['0'], 'options' => $categories, 'empty' => ' ( Category ) '));
}else{
echo $this->Form->input('cid', array('label' => false, 'options' => $categories, 'empty' => ' ( Category ) '));
}
Also, in my controller I've tried this:
$this->params['named']['cid'] = $this->params['pass']['0'];
but I get this error: Indirect modification of overloaded element of CakeRequest has no effect
I believe the plugin automatically sets the selected value if using named params, unless thats a default behavior of cake. How can I convert the passed params to named params, or can I force my plugin to use passed params?
output from var_dump($this->$params):
object(CakeRequest)[9]
public 'params' =>
array
'plugin' => null
'controller' => string 'products' (length=8)
'action' => string 'category' (length=8)
'named' =>
array
empty
'pass' =>
array
0 => string '2' (length=1)
1 => string 'This_and_that' (length=13)
'cid' => string '2' (length=1)
'slug' => string 'This_and_that' (length=13)
public 'data' =>
array
empty
public 'query' =>
array
empty
Thanks

CakePHP inputDefaults and rewrite by field

I've created a large form in Cake and set default options via inputDefaults. However I wish to change the default values for an individual field.
In setting the form defaults, I wrote approximately this:
'inputDefaults' => array(
'error' => array(
'attributes' => array(
'wrap' => 'span',
'class' => 'invalidate column-7 offset-3')));
...with the result that all like fields produce the same error message. But, when I attempt to change the defaults for a single field, like so:
echo $this->Form->input('name', array(
'error' => array(
'attributes' => array(
'wrap' => 'span',
'class' => 'invalidate column-10'))));
It doesn't work. The field name produces an error whose class reads column-7 and offset-3, whereas I'd intended column-10.
Anybody know a solution?
$options['inputDefaults'] You can declare a set of default options for input() with the inputDefaults key to customize your default input creation:
echo $this->Form->create('User', array(
'inputDefaults' => array(
'label' => false,
'div' => false
)
));
All inputs created from that point forward would inherit the options declared in inputDefaults. You can override the defaultOptions by declaring the option in the input() call:
echo $this->Form->input('password'); // No div, no label
// has a label element
echo $this->Form->input(
'username',
array('label' => 'Username')
);

CakePHP 1.2 - Model validation database table field prefixed with id

Inspect the 'Qty' form input with Firebug
<input id "Item0Quantity">
I am having difficult validating this element produced by this code:
<?php echo $form->input("Item.$id.quantity.", array('label' => 'Qty', 'class' => 'txt'));?>
I am working with a form input element that is prefixed with the database table name (Item) and a unique id, the reason for this is to add some JavaScript functionality. Though it still needs CakePHP validation on the Item model.
Here is the input form element that needs to be validated:
<?php echo $form->input("Item.$id.quantity.", array('label' => 'Qty', 'class' => 'txt'));?>
So how will the will be written in the items model? My attempt:
'Item.$id.quantity' => array(
'rule' => 'numeric',
'allowEmpty' => true,
'message' => 'quanitity mut be numeric'
),
The validation will look the same, still by just the field name:
'quantity' => array(
'rule' => 'numeric',
'allowEmpty' => true,
'message' => 'quanitity mut be numeric'
),
When you use saveAll Cake will iterate through each Item and validate it accordingly.

Resources