Creating a CFormModel from generic XML

Hello,

I’m trying to create a CFormModel from a generic XML file and have got really close, but don’t know how to resolve this error.

My XML file looks something like this:




<?xml version="1.0" encoding="UTF-8"?>

<root>

	<services>

		<!-- Name and id for the form -->

		<name>services</name>

		<id>services</id>

		<!-- Input values -->

		<input name="imccURL" id="imccURL" label="" type="">

		    <help></help>

			<value></value>

		</input>

		<input name="storageService" id="storageService" label="" type="">

			<help></help>

			<value></value>

		</input>	

		<input name="solrURL" id="solrURL" label="" type="">

			<help></help>

			<value></value>

		</input>

		<input name="flashMediaServer" id="flashMediaServer" label="" type="">

			<help></help>

			<value></value>

		</input>

		<!-- Rules -->

		<rule>

			<attributeList>imccURL, storageService</attributeList>

			<validatorName>required</validatorName>

		</rule>

	</services>

</root>



And my XMLForm looks like this:




class XMLForm extends CFormModel

{

	public $rulesArray;

		

	/*! 

	* \brief Produce a php array to use to construct a html form from an xml config file

	* 

	* \param[in] $xmlFile location of the xml config file

	* \param[in] $name name of the xml node to be used

	* 

	* \retval Array Success 

	* \retval null Failure

	* 

	* 

	*/ 

	public function setFormArray($xmlFile, $name)

	{

		# Check that the xml file can be loaded

		try 

		{

			$xml = simplexml_load_file($xmlFile);

		}

		catch (Exception $e)

		{

			return null;			

		}

		

		$form['attributes']['name'] = (string)($xml->$name->name);

		$form['attributes']['id'] = (string)($xml->$name->id);

		

		# Form the input values

		if(count($xml->$name->input) > 0)

		{

			$i=0;

			

			foreach($xml->$name->input as $input)

			{

				# Every form input should have a name, id, label and type attribute

				$form['inputs'][$i]['name'] = (string)$input['name'];

				$form['inputs'][$i]['id'] = (string)$input['id'];

				$form['inputs'][$i]['label'] = (string)$input['label'];

				$form['inputs'][$i]['type'] = (string)$input['type'];

				

				# Every input should also have a help description and a value

				$form['inputs'][$i]['help'] = (string)$input->help;

				$form['inputs'][$i]['value'] = (string)$input->value;

				

				$i++;

				

			}

		}

		

		# Form rules

		if(count($xml->$name->rule) > 0)

		{

			$j=0;

			

			foreach($xml->$name->rule as $rule)

			{

				$form['rules'][$j][0] = (string)$rule->attributeList;

				$form['rules'][$j][1] = (string)$rule->validatorName;

			}

			

		}

		

		$this->rulesArray = $form['rules'];

		

		return $form;

	}

	

	public function rules()

	{

		return $this->rulesArray;		

	}

	

	

	

}



When I try and use the form with the CActiveForm widget in the view I get the following error:

‘Property “XMLForm.imccURL” is not defined.’

Which means that I should have put something like this in the XMLForm class:




class XMLForm extends CFormModel

{

	public $imccURL;



BUT I want this to be generic - is there anyway I can declare a property for the XMLForm class from the setFormArray() fucntion?

Or is there any other way people can think of to do it?

Thanks,

G

Yes, your can your use __get and __set php magic functions:




protected $properties=array();

public function __get($name){

if(isset($this->properties[$name]))

return $this->properties[$name];

return parent::__get($name);

}


public function __set($name,$value)

{

if(isset($this->properties[$name]))

{

return $this->properties[$name]=$value;

}

return parent::__set($name,$value);

}



Thanks for that.

I’m still getting the same error though - have I done something daft here? My XMLForm class now reads:


class XMLForm extends CFormModel

{

	public $rulesArray;

	

	protected $properties=array();

	

	public function __get($name)

	{

		if(isset($this->properties[$name]))

		{

			return $this->properties[$name];

		}

		

		return parent::__get($name);

	}

	

	public function __set($name,$value)

	{

		if(isset($this->properties[$name]))

		{

			return $this->properties[$name]=$value;

		}

		

		return parent::__set($name,$value);

	}

		

	/*! 

	* \brief Produce a php array to use to construct a html form from an xml config file

	* 

	* \param[in] $xmlFile location of the xml config file

	* \param[in] $name name of the xml node to be used

	* 

	* \retval Array Success 

	* \retval null Failure

	* 

	* 

	*/ 

	public function setFormArray($xmlFile, $name)

	{

		# Check that the xml file can be loaded

		try 

		{

			$xml = simplexml_load_file($xmlFile);

		}

		catch (Exception $e)

		{

			return null;			

		}

		

		$form['attributes']['name'] = (string)($xml->$name->name);

		$form['attributes']['id'] = (string)($xml->$name->id);

		

		# Form the input values

		if(count($xml->$name->input) > 0)

		{

			$i=0;

			

			foreach($xml->$name->input as $input)

			{

				# Every form input should have a name, id, label and type attribute

				$form['inputs'][$i]['name'] = (string)$input['name'];

				$form['inputs'][$i]['id'] = (string)$input['id'];

				$form['inputs'][$i]['label'] = (string)$input['label'];

				$form['inputs'][$i]['type'] = (string)$input['type'];

				

				# Every input should also have a help description and a value

				$form['inputs'][$i]['help'] = (string)$input->help;

				$form['inputs'][$i]['value'] = (string)$input->value;

				

				$i++;

				

			}

		}

		

		# Form rules

		if(count($xml->$name->rule) > 0)

		{

			$j=0;

			

			foreach($xml->$name->rule as $rule)

			{

				$form['rules'][$j][0] = (string)$rule->attributeList;

				$form['rules'][$j][1] = (string)$rule->validatorName;

			}

			

		}

		

		$this->rulesArray = $form['rules'];

		

		return $form;

	}

	

	public function rules()

	{

		return $this->rulesArray;		

	}

	

	

	

}

And the services action is just the same:


public function actionServices()

	{

		$model = new XMLForm;

		

				# create the php array for the form

		$this->formArray = $model->setFormArray(Yii::app()->params['xmlConfig'], 'services');

		

		

		// renders the view file 'protected/admin/views/settings/services.php'

		// using the default layout 'protected/admin/views/layouts/main.php'

		$this->render('services',array('model'=>$model));

	}

With a pretty standard view:


<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>$this->formArray['attributes']['id'],

	'enableClientValidation'=>true,

	'clientOptions'=>array(

		'validateOnSubmit'=>true,

	),

)); ?>


	<?php echo $form->errorSummary($model); ?>

	

	<?php 

		foreach($this->formArray['inputs'] as $input)

		{

			echo $form->labelEx($model, $input['name']);

			echo $form->textField($model, $input['name']);

			#echo $form->error($model, $input['name']);

			echo "<br />";

		}

	?>

	

	<?php echo CHtml::submitButton('Submit'); ?>


<?php $this->endWidget(); ?>

Removed the if statements in the __get and __set methods and all seems well. So it reads:




public function __get($name)

	{

	  return $this->properties[$name];

	}


public function __set($name, $value)

	{

	  $this->properties[$name]=$value;

	}



Thanks,

G

Hi there, I am newbie and I am trying to do some project for school having the same purpose as yours and I cannot understand how does all these classes relate to each other. For example what are you configuring in parameter ‘xmlConfig’ ? Can you share your solution ?

Greetings Mario