I need to build up a form basing on app configuration (array, not a model) and I wonder is there any way to hire CFrom (Form Builder) for this purpose or do I have to use CHtml instead? Using Form Builder chapter in Official Guide seems to be focused on using model.
I’ve looked into source code of CForm->__construct() method and found out that model is NULL there by default, which lead me to a conclusion that it is possible to use CForm without a model. But when I used code like this:
$form_config = array
(
'title'=>'Please provide your login credential',
'elements'=>array
(
'username'=>array
(
'type'=>'text',
'maxlength'=>32,
),
'password'=>array
(
'type'=>'password',
'maxlength'=>32,
),
)
);
$form = new CForm($form_config);
$form->render();
All I got is “Fatal error: Call to a member function isAttributeSafe() on a non-object”. Which seems to be telling me that using CForm without model isn’t that good idea.
class ConfigForm extends CFormModel
{
public $pagesize;
public $hg_executable;
public $python_path;
public $default_scm;
public $default_timezone;
/**
* Declares the validation rules.
*/
public function rules()
{
return array(
array('pagesize, hg_executable, python_path, default_scm, default_timezone', 'required'),
);
}
/**
* Declares customized attribute labels.
* If not declared here, an attribute would have a label that is
* the same as its name with the first letter in upper case.
*/
public function attributeLabels()
{
return array(
'pagesize'=>'Page Size',
'hg_exectutable' => 'Path to hg exectuable',
'python_path' => 'Python path environment variable',
'default_scm' => 'Default Source Control Provider',
'default_timezone' => 'Default Timezone',
);
}
public function save() {
Yii::app()->config->set('hg_executable', $this->hg_executable);
Yii::app()->config->set('defaultPagesize', $this->pagesize);
Yii::app()->config->set('python_path', $this->python_path);
Yii::app()->config->set('default_timezone', $this->default_timezone);
Yii::app()->config->set('default_scm', $this->default_scm);
return true;
}
}
Since I’m at a very early stage of application development my configuration structure (divided into groups, therefore not so simple as in your example) may and will change a lot. That is main reason, why I don’t want to use model, as I will have to update it’s definition each time something will change in configuration structure.
When using array + foreach for form contents generation approach I have this luck, that any change to configuration structure file will be automatically reflected to form. I.e. I only need to change configuration structure file in my approach (form is auto-generated) and I have to change both model declaration and form viewthat relies on it, when using yours - i.e. model-based approach.
Plus the fact that building configuration groups, subgroups and items using model would in my opinion cost much more coding time than achieving it via arrays and auto-form generation.
But since the approach of using CHtml also seems to be failing (with such basic problems like, how to process forms generated this way) I see that I will not be probably able to avoid using models, which isn’t the thing that makes me really happy! Plus that broken coffee machine, aarrgh!
This seems to be the worst part. Is there any way to have a form model declared the way all its properties will be not as separate variables but as an array (I know, I’m dreaming right now!)? I.e.:
We could create a class that actually renders a form. I try to build a simple skeleton, you develop from there:
class EDynamicForm extends CWidget{
// attribute = array('name'=>'','value'=>'',
// 'type'=>'text|radio|textarea|select',
// 'items'=>array()<--if select,
// 'htmlOptions'=>array())
public $attributes = array();
public $id = null;
public $enctype = null;
public $action = null;
public $model_name = '';
public $method = 'post';
// you put as many properties as needed
public function init(){
// init procedures here
}
public function run(){
// here render procedures
echo CHtml::beginForm($this->action,
$this->method,
array('id'=>$this->id,
'enctype'=>$this->enctype,
'target'=>$this->target));
// you better create a function but
// for the sake of the example...
foreach($this->attributes as $attr)
{
// here we can actually say i
// this is very simple but you get the idea
if($attr['type']=='text')
echo CHtml::textField(ucfirst(strtolower($this->model_name)).'['.$attr['name'].']',$attr['value'],$attr['htmlOptions']);
// do more here
}
echo CHtml::endForm();
}
}
That way you have a dynamic Form widget that you can set as:
$this->widget(‘EDynamicForm’,array(‘id’=>…
On submission
$model->attributes = $_POST[‘model_name’];
I do not know if it helps… good luck with the Coffee
Update:
You know what? I think this could a be a great extension (having form elements displayed with item view templates).
Yes, your idea is really good and for sure it needs my further investigation! Thank you! I just wonder if we are not developing a new version of Form Builder or something similar to it!
Well… I investigated that, but found it less useful. A new form model for each config entry? Wouldn’t be that a waste of time and coding? What if you’ll have 500 config entries like in application I’m developing? I think you could die doing this on form model and tabular input approach…
That is exactly what I was wondering… I think that speed is key for all of us, can you imagine creating a form with a snap. I have my head thinking around this and I think that a Form also -would be nice to have two ways of doing it, could be actually created just by having a model as a parameter too.
Imagine the model is a property and the Form loops through its metaData and creates the fields according to the types describes on its columns (http://www.yiiframework.com/doc/api/1.1/CDbColumnSchema). Of course, user could overwrite field render properties by forcing a form element type…
What do you think? Am I going to far? But Imagine one view like this:
Yii::import(‘EForm’);
EForm::render($model,array(‘action’=>‘controller/action’)); // I do not include anything related to forcing field types
They say, the only sky is the limit! And in Star Trek it is said, that only space is the final frontier!
In other words, if you have time and are enough enthusiastic to write such extension I will greet you with all my hands up. This will for sure add something to Yii community. For me personally this is too much. Similarly to you, I got, what I wanted to get, with using CHtml and processing such forms with $_POST array. I don’t need anything more and even if I would need, I unfortunately haven’t got time for that!
Keeping my thumbs up for you! You’re doing wonderful job for Yii community. Cheers!