CForm without model

Hi there,

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.

Hi Trej

I was wondering why don’t you create a widget that based on the property attributes, renders a Form using a view or CHtml.

Just an idea

Use a form model.

I use one :


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;

    	}

}

As you can see, you can do anything. :)

ANY idea is worth exploring. Can you be a bit more specific or point me to some example (sorry, the coffee machine is down today and so do I! :/)…

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! :confused: Plus that broken coffee machine, aarrgh! :confused:

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.:


class ConfigForm extends CFormModel

{

    	public $config_fields = array('pagesize', 'hg_executable', 'python_path', 'default_scm', 'default_timezone');

...

		return array(

			array(array('pagesize', 'hg_executable', 'python_path', 'default_scm', 'default_timezone'), 'required'),

		);

}

Where array in both cases could be generated dynamically?

No, it isn’t possible, right?

Hi there Trej,

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

I am wondering if one could do this by using the technique described here:

Collecting Tabular Input

If every config entry is a formmodel this should work, shouldn’t it?

When my configuration grows, I am probably going to need this too. :)

<edit>

And that’s pretty much what you were proposing, Antonio.

</edit>

Hi Antonio,

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

or

$this->widget(‘EForm’,array(‘model’=>$model,‘action’=>‘controller/action’));

woaw…

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!

Thanks Trej, there are a lot of members doing so much… (couple of them already helped me to solve tons of issues)

Anyway, I write this idea down… I may jump on it as I think that, for lazy guys like me, could speed up the way we do things.

Cheers!