Creating a dropDownList

Hello guys! I've been exploring Yii for about three hours and I can proudly say that I now understand the framework much better when it comes to parameters and so on. I create a method in the model, which extracts cities(from table "cities") in DB, using custom query. Then, I have the same method in the controller, so that I can call it for example on actionCreate. I am passing the result array with cities to the create View and it passes it as an argument to the _form.

I saw a topic, create by another person, here on the forum, from where I got the idea for cHTML :: listData

This is my result.



<?php //echo CHtml::activeLabelEx($userfirms,'CITY_ID'); ?>


<?php //echo CHtml::activeTextField($userfirms,'CITY_ID'); 





//print_r($cities); 





?>


</div>


<div class="simple">








<?php echo CHtml::activeLabelEx($userfirms,'CITY_ID'); ?>


<?php echo CHtml::activeDropDownList($userfirms,'CITY_ID', CHtml::listData($cities, 'CITY_ID', 'TITLE'), array('size'=>1,


'width'=>50)); ?>


</div>


I dunno why it behaves this way. If I use just $cities, the result is awful, but it tends to work.

I mean, each option is created twice, once containing the ID, second time containing the value(title) of the city.

What am I missing?

Penko

What is $cities? Is it an array of AR objects?

No, Qiang, it is just an variable(particularly an array, passed by render). Thus.



<?php echo $this->renderPartial('_form', array(


	'userfirms'=>$userfirms,


	'cities'=>$cities,


	'update'=>false,


If you want more backwards



	$cities = $this->loadCities();


		


		$this->render('create',array('userfirms'=>$userfirms, 'cities'=>$cities))


And the method in the Controller



	public function loadCities(){


	$this->_cities=UserFirms::model()->loadCities();


	


	return $this->_cities;


	}


And finally the method in the model which the controller refers to.



	public function loadCities(){


	$sql="SELECT * FROM cities";


$command=$this->dbConnection->createCommand($sql);


$cities = $command->queryAll();





return $cities;


	}


Is my way of developing normal or there is more simple solution and implementation after all than mine?

You can define a City AR class and then you can obtain city list simply by: City::model()->findAll().

The listData method expects a list of model objects, not arrays.

I didn't think it's appropriate to create an entire separate class only for cities, that's why I implemented this solution. Do you mean direct receiving from view, or I should pass through controller?

This thing with the cities could be used on several more locations, so, can I define it as a component or I won't be able to use Active Record extending in this case?

I simply want to assign which to be the value of the select option and which to be the ID, so if you could, say, which is the best way, in your view.

For this simple case, I think using AR to represent City is very appropriate. In fact, for every database table, if it represents a collection of objects, you may consider creating an AR class so that your PHP code looks much cleaner. With City class, you no longer need to write those SELECT statements here and there.

Anyway, if you still don't like a separate class for City, I just checked in an enhancement to CHtml::listData() so that it can be used with the results returned by CDbCommand::queryAll().

Thanks, Qiang!

Probably, the implementation you are advising me to use is much better than mine. Will try with writing a separate AR class for cities.

Last and probably dummy question, do I have direct access from views to models, because as you see, in this particular case, you don't have to control anything, so a controller seems unnecessary. But, alternatively, I will keep everything as it is now and will just modify the model's loadCities method, so that it calls the cities AR class, instead of performing a custom SELECT query.

Use $this.

Hm, I seems to have resolved it, but I am not sure this is the idea of the MVC, I am performing relays from Model directly to View, without using Controller, so dunno whether this is proper implementation.

Here is the result of the success.

Posted Image

In the view:

<?php echo CHtml::activeDropDownList($userfirms,'CITY_ID', CHtml::listData(Cities::model()->findAll(), 'CITY_ID','TITLE'), array('size'=>1,


'width'=>50)); ?>


<?php





class Cities extends CActiveRecord


{





	/**


	 * Returns the static model of the specified AR class.


	 * @return CActiveRecord the static model class


	 */


	public static function model($className=__CLASS__)


	{


		return parent::model($className);


	}





	/**


	 * @return string the associated database table name


	 */


	public function tableName()


	{


		return 'cities';


	}





	/**


	 * @return array validation rules for model attributes.


	 */


	public function rules()


	{


		return array(


		//	array('FIRM_NAME','length','max'=>30),


			//array('FIRM_URL','length','max'=>60),


			//array('TELEPHONE','length','max'=>25),


			//array('TELEPHONE2','length','max'=>25),


			//array('FAX','length','max'=>25),


			//array('USER_ID, CITY_ID, FIRM_NAME, FIRM_ACTIVITY, FIRM_URL, ADDRESS, TELEPHONE, TELEPHONE2, FAX', 'required'),


			//array('USER_ID, CITY_ID', 'numerical', 'integerOnly'=>true),


		);


	}





	/**


	 * @return array relational rules.


	 */


	public function relations()


	{


		return array(


		);


	}





	/**


	 * @return array customized attribute labels (name=>label)


	 */


	public function attributeLabels()


	{


		return array(


		);


	}


	


}


It's fine as long as you don't put too complicated logic inside view.

Ok, thanks for the help Qiang.