1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\I18n\View\Helper;
11
12use Locale;
13use NumberFormatter;
14use Zend\I18n\Exception;
15use Zend\View\Helper\AbstractHelper;
16
17/**
18 * View helper for formatting currency.
19 */
20class CurrencyFormat extends AbstractHelper
21{
22    /**
23     * The 3-letter ISO 4217 currency code indicating the currency to use
24     *
25     * @var string
26     */
27    protected $currencyCode;
28
29    /**
30     * Formatter instances
31     *
32     * @var array
33     */
34    protected $formatters = array();
35
36    /**
37     * Locale to use instead of the default
38     *
39     * @var string
40     */
41    protected $locale;
42
43    /**
44     * Currency pattern
45     *
46     * @var string
47     */
48    protected $currencyPattern;
49
50    /**
51     * If set to true, the currency will be returned with two decimals
52     *
53     * @var bool
54     */
55    protected $showDecimals = true;
56
57    /**
58     * @throws Exception\ExtensionNotLoadedException if ext/intl is not present
59     */
60    public function __construct()
61    {
62        if (!extension_loaded('intl')) {
63            throw new Exception\ExtensionNotLoadedException(sprintf(
64                '%s component requires the intl PHP extension',
65                __NAMESPACE__
66            ));
67        }
68    }
69
70    /**
71     * Format a number
72     *
73     * @param  float  $number
74     * @param  string $currencyCode
75     * @param  bool   $showDecimals
76     * @param  string $locale
77     * @param  string $pattern
78     * @return string
79     */
80    public function __invoke(
81        $number,
82        $currencyCode = null,
83        $showDecimals = null,
84        $locale = null,
85        $pattern = null
86    ) {
87        if (null === $locale) {
88            $locale = $this->getLocale();
89        }
90        if (null === $currencyCode) {
91            $currencyCode = $this->getCurrencyCode();
92        }
93        if (null === $showDecimals) {
94            $showDecimals = $this->shouldShowDecimals();
95        }
96        if (null === $pattern) {
97            $pattern = $this->getCurrencyPattern();
98        }
99
100        return $this->formatCurrency($number, $currencyCode, $showDecimals, $locale, $pattern);
101    }
102
103    /**
104     * Format a number
105     *
106     * @param  float  $number
107     * @param  string $currencyCode
108     * @param  bool   $showDecimals
109     * @param  string $locale
110     * @param  string $pattern
111     * @return string
112     */
113    protected function formatCurrency(
114        $number,
115        $currencyCode,
116        $showDecimals,
117        $locale,
118        $pattern
119    ) {
120        $formatterId = md5($locale);
121
122        if (!isset($this->formatters[$formatterId])) {
123            $this->formatters[$formatterId] = new NumberFormatter(
124                $locale,
125                NumberFormatter::CURRENCY
126            );
127        }
128
129        if ($pattern !== null) {
130            $this->formatters[$formatterId]->setPattern($pattern);
131        }
132
133        if ($showDecimals) {
134            $this->formatters[$formatterId]->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
135        } else {
136            $this->formatters[$formatterId]->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
137        }
138
139        return $this->formatters[$formatterId]->formatCurrency($number, $currencyCode);
140    }
141
142    /**
143     * The 3-letter ISO 4217 currency code indicating the currency to use
144     *
145     * @param  string $currencyCode
146     * @return CurrencyFormat
147     */
148    public function setCurrencyCode($currencyCode)
149    {
150        $this->currencyCode = $currencyCode;
151        return $this;
152    }
153
154    /**
155     * Get the 3-letter ISO 4217 currency code indicating the currency to use
156     *
157     * @return string
158     */
159    public function getCurrencyCode()
160    {
161        return $this->currencyCode;
162    }
163
164    /**
165     * Set the currency pattern
166     *
167     * @param  string $currencyPattern
168     * @return CurrencyFormat
169     */
170    public function setCurrencyPattern($currencyPattern)
171    {
172        $this->currencyPattern = $currencyPattern;
173        return $this;
174    }
175
176    /**
177     * Get the currency pattern
178     *
179     * @return string
180     */
181    public function getCurrencyPattern()
182    {
183        return $this->currencyPattern;
184    }
185
186    /**
187     * Set locale to use instead of the default
188     *
189     * @param  string $locale
190     * @return CurrencyFormat
191     */
192    public function setLocale($locale)
193    {
194        $this->locale = (string) $locale;
195        return $this;
196    }
197
198    /**
199     * Get the locale to use
200     *
201     * @return string|null
202     */
203    public function getLocale()
204    {
205        if ($this->locale === null) {
206            $this->locale = Locale::getDefault();
207        }
208
209        return $this->locale;
210    }
211
212    /**
213     * Set if the view helper should show two decimals
214     *
215     * @param  bool $showDecimals
216     * @return CurrencyFormat
217     */
218    public function setShouldShowDecimals($showDecimals)
219    {
220        $this->showDecimals = (bool) $showDecimals;
221        return $this;
222    }
223
224    /**
225     * Get if the view helper should show two decimals
226     *
227     * @return bool
228     */
229    public function shouldShowDecimals()
230    {
231        return $this->showDecimals;
232    }
233}
234