lrzins Posted January 14, 2013 Share Posted January 14, 2013 Hi, I've created a drop down list of user's names, that I've concatenated from first_name and last_name in a database table. And it works perfectly! Here's what I've got: User Model: public function getFullName() { return $this->first_name . " " . $this->last_name; } StudentRecordController, in actionCreate(): $students = CHtml::listData(User::model()->with('studentRecords')->findAll(), 'id', 'FullName'); And in views/studentRecord/_form.php: <?php echo $form->dropDownList($model, 'user_id', $students, array('empty' => 'Select Student Name')); ?> My question is, how is the getFullName() method called by the third argument to listData, which is 'FullName'? The "get" is parsed out? If I use the full method name instead (getFullName), it does'nt work. And actually fullname, fullName, FuLlNaMe all work. Bear in mind, that with this approach, you have to include the $students array in the render method of the controller and the view. Larry Z. Link to comment Share on other sites More sharing options...
Edward Posted January 15, 2013 Share Posted January 15, 2013 When i used cdata to do this i put the logic code into the model within a get method. I then called the method from the model in the view within the dropdown list function if that helps. 1 Link to comment Share on other sites More sharing options...
Edward Posted January 15, 2013 Share Posted January 15, 2013 I had some trouble with CHtml::listData it would not work correctly in one of my situations. So what i done is create an array manually then the sent the array from the model to the dropdown function in the view and it worked perfectly. For example here was some of my model code: public function getShippingServiceOptions() { $list = array(); $list['']='Select a shipping service'; $list['service1']='Economy services from outside US'; $list['1']='Economy Shipping from outside US (11 to 23 business days)'; $list['service2']='Standard services from outside US'; $list['5']='Standard Shipping from outside US (5 to 10 business days)'; $list['service3']='Expedited services from outside US'; $list['10']='Expedited Shipping from outside US (1 to 4 business days)'; $list['econony-services']='Economy Services'; $services = $this->findAll('type=:type', array(':type'=>'economy-service')); foreach($services as $service) { $list[$service->id]=$service->description; } return $list; } I don't think there would be much difference between this and putting together a first name and last name. 1 Link to comment Share on other sites More sharing options...
Antonio Conte Posted January 15, 2013 Share Posted January 15, 2013 @lrzins: The reason it works is because YII will look for model attributes and by convention require you to have a get-method for it. You can argue both ways if this is a good solution, but currently you just need to know that's how it works. The reason different versions of caps/similar also works, must be because YII applies some String operations there. 2 Link to comment Share on other sites More sharing options...
Edward Posted January 15, 2013 Share Posted January 15, 2013 Ah yeah and about the get the root of all yii classes extend from the Ccomponent Class that is where you get or set problem lies. https://github.com/yiisoft/yii/blob/1.1.13/framework/base/CComponent.php /** * Returns a property value, an event handler list or a behavior based on its name. * Do not call this method. This is a PHP magic method that we override * to allow using the following syntax to read a property or obtain event handlers: * <pre> * $value=$component->propertyName; * $handlers=$component->eventName; * </pre> * @param string $name the property name or event name * @return mixed the property value, event handlers attached to the event, or the named behavior * @throws CException if the property or event is not defined * @see __set */ public function __get($name) { $getter='get'.$name; if(method_exists($this,$getter)) return $this->$getter(); elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) { // duplicating getEventHandlers() here for performance $name=strtolower($name); if(!isset($this->_e[$name])) $this->_e[$name]=new CList; return $this->_e[$name]; } elseif(isset($this->_m[$name])) return $this->_m[$name]; elseif(is_array($this->_m)) { foreach($this->_m as $object) { if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name))) return $object->$name; } } throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.', array('{class}'=>get_class($this), '{property}'=>$name))); } /** * Sets value of a component property. * Do not call this method. This is a PHP magic method that we override * to allow using the following syntax to set a property or attach an event handler * <pre> * $this->propertyName=$value; * $this->eventName=$callback; * </pre> * @param string $name the property name or the event name * @param mixed $value the property value or callback * @return mixed * @throws CException if the property/event is not defined or the property is read only. * @see __get */ public function __set($name,$value) { $setter='set'.$name; if(method_exists($this,$setter)) return $this->$setter($value); elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) { // duplicating getEventHandlers() here for performance $name=strtolower($name); if(!isset($this->_e[$name])) $this->_e[$name]=new CList; return $this->_e[$name]->add($value); } elseif(is_array($this->_m)) { foreach($this->_m as $object) { if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name))) return $object->$name=$value; } } if(method_exists($this,'get'.$name)) throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.', array('{class}'=>get_class($this), '{property}'=>$name))); else throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.', array('{class}'=>get_class($this), '{property}'=>$name))); } 1 Link to comment Share on other sites More sharing options...
Antonio Conte Posted January 15, 2013 Share Posted January 15, 2013 Elementary, my dear Watson. Good job, Edward. 1 Link to comment Share on other sites More sharing options...
lrzins Posted January 15, 2013 Author Share Posted January 15, 2013 Thanks Edward and Antonio, that explains it. As Edward suggested, I moved the code from the controller into the model, and now have: In models/StudentRecord.php public function getStudentNames() { return CHtml::listData(User::model()->with('studentRecords')->findAll(), 'id', 'FullName'); } In models/User.php public function getFullName() { return $this->first_name . " " . $this->last_name; } And in views/studentRecord/_form.php <?php echo $form->dropDownList($model, 'user_id', $model->getStudentNames(), array('empty' => 'Select Student Name')); ?> I think this is a good way to do it. It's nice to know about the convention of adding "get" to the method names (why and where). Best regards, Larry Z. Link to comment Share on other sites More sharing options...
Recommended Posts