1: <?php
2: /**
3: * CFormatter class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CFormatter provides a set of commonly used data formatting methods.
13: *
14: * The formatting methods provided by CFormatter are all named in the form of <code>formatXyz</code>.
15: * The behavior of some of them may be configured via the properties of CFormatter. For example,
16: * by configuring {@link dateFormat}, one may control how {@link formatDate} formats the value into a date string.
17: *
18: * For convenience, CFormatter also implements the mechanism of calling formatting methods with their shortcuts (called types).
19: * In particular, if a formatting method is named <code>formatXyz</code>, then its shortcut method is <code>xyz</code>
20: * (case-insensitive). For example, calling <code>$formatter->date($value)</code> is equivalent to calling
21: * <code>$formatter->formatDate($value)</code>.
22: *
23: * Currently, the following types are recognizable:
24: * <ul>
25: * <li>raw: the attribute value will not be changed at all.</li>
26: * <li>text: the attribute value will be HTML-encoded when rendering.</li>
27: * <li>ntext: the {@link formatNtext} method will be called to format the attribute value as a HTML-encoded plain text with newlines converted as the HTML <br /> or <p></p> tags.</li>
28: * <li>html: the attribute value will be purified and then returned.</li>
29: * <li>date: the {@link formatDate} method will be called to format the attribute value as a date.</li>
30: * <li>time: the {@link formatTime} method will be called to format the attribute value as a time.</li>
31: * <li>datetime: the {@link formatDatetime} method will be called to format the attribute value as a date with time.</li>
32: * <li>boolean: the {@link formatBoolean} method will be called to format the attribute value as a boolean display.</li>
33: * <li>number: the {@link formatNumber} method will be called to format the attribute value as a number display.</li>
34: * <li>email: the {@link formatEmail} method will be called to format the attribute value as a mailto link.</li>
35: * <li>image: the {@link formatImage} method will be called to format the attribute value as an image tag where the attribute value is the image URL.</li>
36: * <li>url: the {@link formatUrl} method will be called to format the attribute value as a hyperlink where the attribute value is the URL.</li>
37: * <li>size: the {@link formatSize} method will be called to format the attribute value, interpreted as a number of bytes, as a size in human readable form.</li>
38: * </ul>
39: *
40: * By default, {@link CApplication} registers {@link CFormatter} as an application component whose ID is 'format'.
41: * Therefore, one may call <code>Yii::app()->format->boolean(1)</code>.
42: * You might want to replace this component with {@link CLocalizedFormatter} to enable formatting based on the
43: * current locale settings.
44: *
45: * @property CHtmlPurifier $htmlPurifier The HTML purifier instance.
46: *
47: * @author Qiang Xue <qiang.xue@gmail.com>
48: * @package system.utils
49: * @since 1.1.0
50: */
51: class CFormatter extends CApplicationComponent
52: {
53: /**
54: * @var CHtmlPurifier
55: */
56: private $_htmlPurifier;
57:
58: /**
59: * @var string the format string to be used to format a date using PHP date() function. Defaults to 'Y/m/d'.
60: */
61: public $dateFormat='Y/m/d';
62: /**
63: * @var string the format string to be used to format a time using PHP date() function. Defaults to 'h:i:s A'.
64: */
65: public $timeFormat='h:i:s A';
66: /**
67: * @var string the format string to be used to format a date and time using PHP date() function. Defaults to 'Y/m/d h:i:s A'.
68: */
69: public $datetimeFormat='Y/m/d h:i:s A';
70: /**
71: * @var array the format used to format a number with PHP number_format() function.
72: * Three elements may be specified: "decimals", "decimalSeparator" and "thousandSeparator".
73: * They correspond to the number of digits after the decimal point, the character displayed as the decimal point
74: * and the thousands separator character.
75: */
76: public $numberFormat=array('decimals'=>null, 'decimalSeparator'=>null, 'thousandSeparator'=>null);
77: /**
78: * @var array the text to be displayed when formatting a boolean value. The first element corresponds
79: * to the text display for false, the second element for true. Defaults to <code>array('No', 'Yes')</code>.
80: */
81: public $booleanFormat=array('No','Yes');
82: /**
83: * @var array the options to be passed to CHtmlPurifier instance used in this class. CHtmlPurifier is used
84: * in {@link formatHtml} method, so this property could be useful to customize HTML filtering behavior.
85: * @since 1.1.13
86: */
87: public $htmlPurifierOptions=array();
88: /**
89: * @var array the format used to format size (bytes). Three elements may be specified: "base", "decimals" and "decimalSeparator".
90: * They correspond to the base at which a kilobyte is calculated (1000 or 1024 bytes per kilobyte, defaults to 1024),
91: * the number of digits after the decimal point (defaults to 2) and the character displayed as the decimal point.
92: * "decimalSeparator" is available since version 1.1.13
93: * @since 1.1.11
94: */
95: public $sizeFormat=array(
96: 'base'=>1024,
97: 'decimals'=>2,
98: 'decimalSeparator'=>null,
99: );
100:
101: /**
102: * Calls the format method when its shortcut is invoked.
103: * This is a PHP magic method that we override to implement the shortcut format methods.
104: * @param string $name the method name
105: * @param array $parameters method parameters
106: * @return mixed the method return value
107: */
108: public function __call($name,$parameters)
109: {
110: if(method_exists($this,'format'.$name))
111: return call_user_func_array(array($this,'format'.$name),$parameters);
112: else
113: return parent::__call($name,$parameters);
114: }
115:
116: /**
117: * Formats a value based on the given type.
118: * @param mixed $value the value to be formatted
119: * @param string $type the data type. This must correspond to a format method available in CFormatter.
120: * For example, we can use 'text' here because there is method named {@link formatText}.
121: * @throws CException if given type is unknown
122: * @return string the formatted data
123: */
124: public function format($value,$type)
125: {
126: $method='format'.$type;
127: if(method_exists($this,$method))
128: return $this->$method($value);
129: else
130: throw new CException(Yii::t('yii','Unknown type "{type}".',array('{type}'=>$type)));
131: }
132:
133: /**
134: * Formats the value as is without any formatting.
135: * This method simply returns back the parameter without any format.
136: * @param mixed $value the value to be formatted
137: * @return string the formatted result
138: */
139: public function formatRaw($value)
140: {
141: return $value;
142: }
143:
144: /**
145: * Formats the value as a HTML-encoded plain text.
146: * @param mixed $value the value to be formatted
147: * @return string the formatted result
148: */
149: public function formatText($value)
150: {
151: return CHtml::encode($value);
152: }
153:
154: /**
155: * Formats the value as a HTML-encoded plain text and converts newlines with HTML <br /> or
156: * <p></p> tags.
157: * @param mixed $value the value to be formatted
158: * @param boolean $paragraphs whether newlines should be converted to HTML <p></p> tags,
159: * false by default meaning that HTML <br /> tags will be used
160: * @param boolean $removeEmptyParagraphs whether empty paragraphs should be removed, defaults to true;
161: * makes sense only when $paragraphs parameter is true
162: * @return string the formatted result
163: */
164: public function formatNtext($value,$paragraphs=false,$removeEmptyParagraphs=true)
165: {
166: $value=CHtml::encode($value);
167: if($paragraphs)
168: {
169: $value='<p>'.str_replace(array("\r\n", "\n", "\r"), '</p><p>',$value).'</p>';
170: if($removeEmptyParagraphs)
171: $value=preg_replace('/(<\/p><p>){2,}/i','</p><p>',$value);
172: return $value;
173: }
174: else
175: {
176: return nl2br($value);
177: }
178: }
179:
180: /**
181: * Formats the value as HTML text without any encoding.
182: * @param mixed $value the value to be formatted
183: * @return string the formatted result
184: */
185: public function formatHtml($value)
186: {
187: return $this->getHtmlPurifier()->purify($value);
188: }
189:
190: /**
191: * Formats the value as a date.
192: * @param mixed $value the value to be formatted
193: * @return string the formatted result
194: * @see dateFormat
195: */
196: public function formatDate($value)
197: {
198: return date($this->dateFormat,$this->normalizeDateValue($value));
199: }
200:
201: /**
202: * Formats the value as a time.
203: * @param mixed $value the value to be formatted
204: * @return string the formatted result
205: * @see timeFormat
206: */
207: public function formatTime($value)
208: {
209: return date($this->timeFormat,$this->normalizeDateValue($value));
210: }
211:
212: /**
213: * Formats the value as a date and time.
214: * @param mixed $value the value to be formatted
215: * @return string the formatted result
216: * @see datetimeFormat
217: */
218: public function formatDatetime($value)
219: {
220: return date($this->datetimeFormat,$this->normalizeDateValue($value));
221: }
222:
223: /**
224: * Normalizes an expression as a timestamp.
225: * @param mixed $time the time expression to be normalized
226: * @return int the normalized result as a UNIX timestamp
227: */
228: protected function normalizeDateValue($time)
229: {
230: if(is_string($time))
231: {
232: if(ctype_digit($time) || ($time{0}=='-' && ctype_digit(substr($time, 1))))
233: return (int)$time;
234: else
235: return strtotime($time);
236: }
237: elseif (class_exists('DateTime', false) && $time instanceof DateTime)
238: return $time->getTimestamp();
239: else
240: return (int)$time;
241: }
242:
243: /**
244: * Formats the value as a boolean.
245: * @param mixed $value the value to be formatted
246: * @return string the formatted result
247: * @see booleanFormat
248: */
249: public function formatBoolean($value)
250: {
251: return $value ? $this->booleanFormat[1] : $this->booleanFormat[0];
252: }
253:
254: /**
255: * Formats the value as a mailto link.
256: * @param mixed $value the value to be formatted
257: * @return string the formatted result
258: */
259: public function formatEmail($value)
260: {
261: return CHtml::mailto($value);
262: }
263:
264: /**
265: * Formats the value as an image tag.
266: * @param mixed $value the value to be formatted
267: * @return string the formatted result
268: */
269: public function formatImage($value)
270: {
271: return CHtml::image($value);
272: }
273:
274: /**
275: * Formats the value as a hyperlink.
276: * @param mixed $value the value to be formatted
277: * @return string the formatted result
278: */
279: public function formatUrl($value)
280: {
281: $url=$value;
282: if(strpos($url,'http://')!==0 && strpos($url,'https://')!==0)
283: $url='http://'.$url;
284: return CHtml::link(CHtml::encode($value),$url);
285: }
286:
287: /**
288: * Formats the value as a number using PHP number_format() function.
289: * @param mixed $value the value to be formatted
290: * @return string the formatted result
291: * @see numberFormat
292: */
293: public function formatNumber($value)
294: {
295: return number_format($value,$this->numberFormat['decimals'],$this->numberFormat['decimalSeparator'],$this->numberFormat['thousandSeparator']);
296: }
297:
298: /**
299: * @return CHtmlPurifier the HTML purifier instance
300: */
301: public function getHtmlPurifier()
302: {
303: if($this->_htmlPurifier===null)
304: $this->_htmlPurifier=new CHtmlPurifier;
305: $this->_htmlPurifier->options=$this->htmlPurifierOptions;
306: return $this->_htmlPurifier;
307: }
308:
309: /**
310: * Formats the value in bytes as a size in human readable form.
311: * @param integer $value value in bytes to be formatted
312: * @param boolean $verbose if full names should be used (e.g. bytes, kilobytes, ...).
313: * Defaults to false meaning that short names will be used (e.g. B, KB, ...).
314: * @return string the formatted result
315: * @see sizeFormat
316: * @since 1.1.11
317: */
318: public function formatSize($value,$verbose=false)
319: {
320: $base=$this->sizeFormat['base'];
321: for($i=0; $base<=$value && $i<5; $i++)
322: $value=$value/$base;
323:
324: $value=round($value, $this->sizeFormat['decimals']);
325: $formattedValue=isset($this->sizeFormat['decimalSeparator']) ? str_replace('.',$this->sizeFormat['decimalSeparator'],$value) : $value;
326: $params=array($value,'{n}'=>$formattedValue);
327:
328: switch($i)
329: {
330: case 0:
331: return $verbose ? Yii::t('yii','{n} byte|{n} bytes',$params) : Yii::t('yii', '{n} B',$params);
332: case 1:
333: return $verbose ? Yii::t('yii','{n} kilobyte|{n} kilobytes',$params) : Yii::t('yii','{n} KB',$params);
334: case 2:
335: return $verbose ? Yii::t('yii','{n} megabyte|{n} megabytes',$params) : Yii::t('yii','{n} MB',$params);
336: case 3:
337: return $verbose ? Yii::t('yii','{n} gigabyte|{n} gigabytes',$params) : Yii::t('yii','{n} GB',$params);
338: default:
339: return $verbose ? Yii::t('yii','{n} terabyte|{n} terabytes',$params) : Yii::t('yii','{n} TB',$params);
340: }
341: }
342: }
343: