Best practice to format common strings like username

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?


public function getDisplayName()

{

  return $this->pseudonym." (".$this->first_name." ".$this->last_name.")";

}

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.

in your model its all about retrieving data

use widgets to display your data

ok, thanks. I’ll try to adopt your getDisplayName method now and I’ll create widgets for the additional functionality.

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.

also consider this http://www.yiiframework.com/wiki/227/guidelines-for-good-schema-design/

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.

I don’t agree on 2 topics:

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

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

Ok, I think, now I found a document which explains my problem: This page says:

So, how much HTML is ok?

Later on, that page says something about helper classes for views.

This seems to be something similar to my solution that I presented in my first post. Shouldn’t I keep it?

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.

ok, thanks a lot, that’s what i wanted to know then.

Thank you. This is a perfect response to me also. Sincerely I was thinking a whole day about code+html mixing, especially avoiding html.

I would like to add:




<?php

class AR_Users extends CActiveRecord {


	public static function model($className=__CLASS__) {

		return parent::model($className);

	}


	public function tableName() {

		return 'users';

	}

	

	public function renderName($template = '{first_name} {last_name} ({username})') {

		return str_replace(

			array(

				'{first_name}',

				'{last_name}',

				'{username}',

			),

			array(

				CHtml::encode($this->first_name),

				CHtml::encode($this->last_name),

				CHtml::encode($this->username),

			),

			$template

		);

	}


}

?>