"Percent" View Helper for the Zend Framework
Lately I've been working on a very data-intensive website where things like averages and percentages are very common. While it is pretty simple to display an average, the "percent" format is a little awkward to display easily. Usually, a percent value is calculated within the SQL query and displayed in the view.
SELECT id,
name,
CONCAT(score / max_score * 100, '%', 3) as percent
FROM my_table
WHERE id = 123;
However, I consider "percent" to be a display format, and asking the database to render a "for display" value can lead to design issues in the future.
For example, let's say your client wants to display the score alongside the percent value. Simple enough, just modify your SQL query right? But doing so would mean that a programmer would have be making simple design changes... is there a better way?
One solution would be to fetch the raw values and calculate them in PHP within the view script:
# controller $this-view->exam = $myTable->find(123)->current();
# view <?= number_format($this->exam->score / $this->exam->max_score * 100, 3) ?>%
While that may seem like a pretty simple bit of code, it can be quite tedious to have to write out that formula each time you need a percent value. Additionally, percents like 92.5% would be displayed as 92.500% due to how number_format treats trailing zeroes. To remove trailing zeroes and the possible trailing dot, you must wrap the number_format() function above in two rtrim() functions.
<?= rtrim(rtrim(number_format($this->exam->score / $this->exam->max_score * 100, 3), '0'), '.') ?>%
As you can see, this is starting to look pretty ugly.
That's where the Zend Framework's view helpers come in. They are perfect for these types of things.
Usage
Usage is pretty straightforward. Just pass in an array of values representing the score and max_score values, and an optional integer for the number of digits to keep after the dot.
<?= $this->percent(array($this->exam->score, $this->exam->max_score), 3) ?>
That's it! The view helper automatically handles the calculations for you, trims off any trailing zeroes, and appends a '%' to the end.
The output for the code above would look like 92.5%.
In the event that you already have a percent value (perhaps from a precalculated database field) and just need to have it formatted, pass in the percent value instead of an array. The view helper will detect that it's numeric and just do the trimming and toss a percent sign at the end.
To create percentages in other locales, you can assign your own characters to use for the percent sign, thousands separator, and decimal separator.
<?= $this->percent()
->setPercentSymbol('#')
->setThousandsSeparator('.')
->setDecimalSeparator(',')
->percent(array($this->exam->score, $this->exam->max_score), 3) ?>
The output for the above would look like 92,5#.
Here's the complete Percent view helper for the Zend Framework.
Virgen_View_Helper_Percent
<?php
/**
* Formats a number to pretty percent notation.
* Accepts an array of numbers to calculate on-the-fly
*
* @author Hector Virgen
*/
class Virgen_View_Helper_Percent
{
/**
* Flag to enable/disable trimming of trailing zeroes and dot
*
* @var boolean
*/
protected $_trimTrail = true;
/**
* Percent symbol to append to formatted number
*
* @var string
*/
protected $_symbol = '%';
/**
* Character to use as thousands separator
*
* @var string
*/
protected $_thousandsSep = ',';
/**
* Character to use as decimal point
*
* @var string
*/
protected $_decPoint = '.';
/**
* Formats a number or array of numbers to percent notation
*
* @param numeric|array $data - Percent value or array of numbers to calculate percent
* @param int $digits - Number of digits to display after the dot
* @return string - Formatted percent
*/
public function percent($data = null, $digits = 0)
{
// Return this if no parameters were passed
if (null === $data) {
return $this;
}
// Determine percent value
if (is_array($data)) {
list($val, $maxval) = $data;
$percent = $this->calcPercent($val, $maxval);
} else if (is_numeric($data)) {
$percent = (float) $data;
} else {
throw new Zend_View_Exception("Data must be a numeric or array of value, maxvalue.");
}
$percent = (string) number_format($percent, (int) $digits, $this->_decPoint, $this->_thousandsSep);
// Remove trailing zeroes and dot
if ($this->_trimTrail AND $digits > 0) {
$percent = rtrim($percent, '0');
$percent = rtrim($percent, $this->_decPoint);
}
// Append percent symbol
$percent .= $this->_symbol;
return $percent;
}
/**
* Calculates the percent based on value and maxvalue.
*
* @param numeric $val - Current value
* @param numeric $maxval - Total value
* @return float - percent of total value
*/
public function calcPercent($val, $maxval)
{
$maxval = (float) $maxval;
if (0 == $maxval) {
throw new Zend_View_Exception("Maxval must be a non-zero value.");
}
return (float) $val / $maxval * 100;
}
/**
* Enables or disabled the trimming of trailing zeroes and dots
*
* @param boolean $flag - true or false
* @return $this - Fluent interface
*/
public function setTrimTrail($flag)
{
$this->_trimTrail = (bool) $flag;
return $this;
}
/**
* Sets the symbol to append to the percent value
*
* @param string $symbol - Percent symbol
* @return $this - Fluent interface
*/
public function setSymbol($symbol)
{
$this->_symbol = (string) $symbol;
return $this;
}
/**
* Sets the decimal point character
*
* @param string $char - Decimal point character
* @return $this- Fluent interface
*/
public function setDecPoint($char)
{
$this->_decPoint = (string) $char;
if (empty($this->_decPoint)) {
throw new Zend_View_Exception("Decimal point character cannot be empty.");
}
return $this;
}
/**
* Sets the thousands separator to use
*
* @param string $sep
* @return $this - Fluent interface
*/
public function setThousandsSep($sep)
{
$this->_thousandsSep = $sep;
return $this;
}
} 
Well, you should use your models to get the percent for you instead of doing this helper nor view.
Article is pretty old so im sure youre doing it now ^^
Cheers !
Now that I'm older and (slightly) wiser, I agree. But it's a fine line between presentational functionality and model formatting.
For example, when asking the model for a percent score it may return a float like 97.3972894241. This helper can still come in to format it to something a little prettier, like 97.4%.