3 namespace Drupal\views\Plugin\views\field;
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
7 use Drupal\views\ResultRow;
10 * Render a field as a numeric value
13 * - float: If true this field contains a decimal value. If unset this field
14 * will be assumed to be integer.
16 * @ingroup views_field_handlers
18 * @ViewsField("numeric")
20 class NumericField extends FieldPluginBase {
25 protected function defineOptions() {
26 $options = parent::defineOptions();
28 $options['set_precision'] = ['default' => FALSE];
29 $options['precision'] = ['default' => 0];
30 $options['decimal'] = ['default' => '.'];
31 $options['separator'] = ['default' => ','];
32 $options['format_plural'] = ['default' => FALSE];
33 $options['format_plural_string'] = ['default' => '1' . LOCALE_PLURAL_DELIMITER . '@count'];
34 $options['prefix'] = ['default' => ''];
35 $options['suffix'] = ['default' => ''];
43 public function buildOptionsForm(&$form, FormStateInterface $form_state) {
44 if (!empty($this->definition['float'])) {
45 $form['set_precision'] = [
46 '#type' => 'checkbox',
47 '#title' => $this->t('Round'),
48 '#description' => $this->t('If checked, the number will be rounded.'),
49 '#default_value' => $this->options['set_precision'],
51 $form['precision'] = [
52 '#type' => 'textfield',
53 '#title' => $this->t('Precision'),
54 '#default_value' => $this->options['precision'],
55 '#description' => $this->t('Specify how many digits to print after the decimal point.'),
58 ':input[name="options[set_precision]"]' => ['checked' => TRUE],
64 '#type' => 'textfield',
65 '#title' => $this->t('Decimal point'),
66 '#default_value' => $this->options['decimal'],
67 '#description' => $this->t('What single character to use as a decimal point.'),
71 $form['separator'] = [
73 '#title' => $this->t('Thousands marker'),
75 '' => $this->t('- None -'),
76 ',' => $this->t('Comma'),
77 ' ' => $this->t('Space'),
78 '.' => $this->t('Decimal'),
79 '\'' => $this->t('Apostrophe'),
81 '#default_value' => $this->options['separator'],
82 '#description' => $this->t('What single character to use as the thousands separator.'),
85 $form['format_plural'] = [
86 '#type' => 'checkbox',
87 '#title' => $this->t('Format plural'),
88 '#description' => $this->t('If checked, special handling will be used for plurality.'),
89 '#default_value' => $this->options['format_plural'],
91 $form['format_plural_string'] = [
93 '#default_value' => $this->options['format_plural_string'],
96 $plural_array = explode(LOCALE_PLURAL_DELIMITER, $this->options['format_plural_string']);
97 $plurals = $this->getNumberOfPlurals($this->view->storage->get('langcode'));
98 for ($i = 0; $i < $plurals; $i++) {
99 $form['format_plural_values'][$i] = [
100 '#type' => 'textfield',
101 // @todo Should use better labels https://www.drupal.org/node/2499639
102 '#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')),
103 '#default_value' => isset($plural_array[$i]) ? $plural_array[$i] : '',
104 '#description' => $this->t('Text to use for this variant, @count will be replaced with the value.'),
107 ':input[name="options[format_plural]"]' => ['checked' => TRUE],
113 // Simplify interface text for the most common case.
114 $form['format_plural_values'][0]['#description'] = $this->t('Text to use for the singular form, @count will be replaced with the value.');
115 $form['format_plural_values'][1]['#title'] = $this->t('Plural form');
116 $form['format_plural_values'][1]['#description'] = $this->t('Text to use for the plural form, @count will be replaced with the value.');
120 '#type' => 'textfield',
121 '#title' => $this->t('Prefix'),
122 '#default_value' => $this->options['prefix'],
123 '#description' => $this->t('Text to put before the number, such as currency symbol.'),
126 '#type' => 'textfield',
127 '#title' => $this->t('Suffix'),
128 '#default_value' => $this->options['suffix'],
129 '#description' => $this->t('Text to put after the number, such as currency symbol.'),
132 parent::buildOptionsForm($form, $form_state);
138 public function submitOptionsForm(&$form, FormStateInterface $form_state) {
139 // Merge plural format options into one string and drop the individual
141 $options = &$form_state->getValue('options');
142 $options['format_plural_string'] = implode(LOCALE_PLURAL_DELIMITER, $options['format_plural_values']);
143 unset($options['format_plural_values']);
144 parent::submitOptionsForm($form, $form_state);
150 public function render(ResultRow $values) {
151 $value = $this->getValue($values);
153 // Check to see if hiding should happen before adding prefix and suffix
154 // and before rewriting.
155 if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
159 if (!empty($this->options['set_precision'])) {
160 $precision = $this->options['precision'];
162 elseif ($decimal_position = strpos($value, '.')) {
163 $precision = strlen($value) - $decimal_position - 1;
169 // Use round first to avoid negative zeros.
170 $value = round($value, $precision);
171 // Test against both integer zero and float zero.
172 if ($this->options['empty_zero'] && ($value === 0 || $value === 0.0)) {
176 $value = number_format($value, $precision, $this->options['decimal'], $this->options['separator']);
178 // If we should format as plural, take the (possibly) translated plural
179 // setting and format with the current language.
180 if (!empty($this->options['format_plural'])) {
181 $value = PluralTranslatableMarkup::createFromTranslatedString($value, $this->options['format_plural_string']);
184 return $this->sanitizeValue($this->options['prefix'], 'xss')
185 . $this->sanitizeValue($value)
186 . $this->sanitizeValue($this->options['suffix'], 'xss');