I’d like to know the best practice to do the following:
Whereever the name of a user is shown in my application, I’d like to have it in the format “Bob Miller (bobby65)” where bobby65 is the pseudonym, Bob is the first name and Miller is the last name. My current solution is a helper class in the components-directory which looks as follows:
class UserHelper{
/**
* returns the formatted username
* @param $user User the user's active record
* @param $options array possible options:
* - encode: if true, name will be HTML-coded. default:true
* - link: if true, a link to the user's profile will be generated. default: like encode
* @return string e.g. "Bob Miller (bobby65)"
*/
public static function name($user,$options=array()){
if(!isset($options["encode"])){
$options["encode"]=true;
}
if(!isset($options["link"])){
$options["link"]=$options["encode"];
}
$name=$user->pseudonym." (".$user->first_name." ".$user->last_name.")";
if(!$options["encode"]){
return $name;
}
$return=CHtml::encode($name);
if($options["link"]){
$return=CHtml::link($return,array("profile/view","pseudonym"=>$user->pseudonym));
}
return $return;
}
...
}
There are additional functions to print the user’s photo or to show additional options like “Send message to this user” in UserHelper. I don’t know where to put those neither.
Apart from this static class, I could imagine creating a widget for each function but I think a widget would be something more complex than that. Another solution I found is to put this into a view under protected/views/common, would that be better? I could put the functions into the Model class, too, but this seems not to be the right place to me.
What would you propose as a proper way to do this?
This would be a method of the User model I guess? Then, I would have to add the hyperlink and image-tag there. Is it a good practice to use CHtml methods in the model?
class User extends CActiveRecord
{
...
public function getDisplayName($link=true){
$return=$user->pseudonym." (".$this->first_name." ".$this->last_name.")";
if($link){
$return=CHtml::link($return,array("profile/view","pseudonym"=>$this->pseudonym));
}
return $return;
}
public function getDisplayImageLarge($htmlOptions){
$image=CHtml::image($this->getImagePath(),$this->getDisplayName(),$htmlOptions);
return CHtml::link($image,array("profile/view","pseudonym"=>$this->pseudonym));
}
}
But like this I can’t HTML encode the name any more. so I need to add the CHtml::encode in these functions as in my first post.
Consider including the getFormattedName function in the activeRecord class:
<?php
class AR_Users extends CActiveRecord {
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function tableName() {
return 'users';
}
public function getFormattedName() {
return CHtml::encode($this->first_name.' '.$this->last_name.' ('.$this->username.')');
}
}
?>
We consider the first_name, last_name and username fields being present in your users table.
If the user isn’t known (the data you want to display isn’t an object), you may use a static function also:
<?php
class AR_Users extends CActiveRecord {
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function tableName() {
return 'users';
}
public function getFormattedName() {
return self::formatName($this->first_name, $this->last_name, $this->username);
}
public static function formatName($first, $last, $user = null) {
$u = ($user === null) ? '' : ' ('.$user.')';
return CHtml::encode($first.' '.$last.$u);
}
}
?>
AR_Users::formatName() can be used to format everything as a name.
I have the properties first_name, last_name and pseudonym in my User model. So, the non-static function you proposed would be a good solution, but for my purposes it would be useful to get the formatted name as a hyperlink, e.g.:
<?php
class AR_Users extends CActiveRecord {
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function tableName() {
return 'users';
}
public function getFormattedName() {
return CHtml::link(
CHtml::encode($this->first_name.' '.$this->last_name.' ('.$this->username.')'),
array("profile/view","pseudonym"=>$this->pseudonym)
);
}
}
?>
Does this mean that it is usual to use CHtml functions in a model class? That is what made me hesitate.
You can use what you like in the model class, or everywhere. Regardless of the static/dynamic state of functions/classes, there is no restriction at all, what kind of functions return your needed data.
Tables holding a collection of data should be named in plural. Regardless how do you read the code. So, table users hold the users, not a single user. And so on, files, products, etc.
Custom classes (created/extended) should have a distinctive prefix. When using $bot = new Bot; it’s not self-explaining, what’s the Bot. Just as yii does, with the C prefix, it’s better to prefix ActiveRecords with AR_, or other classes with App, My, etc.
It’s really up to you to make this decision. In my projects i sometimes also create HTML snippets like yours from a model. It’s just for convenience. If your project is not big and you’re sure, that you never access this property from outside the web (e.g. to render a PDF from an offline command or something) i’d say, these little shortcuts are acceptable.