View source
<?php
namespace Drupal\dimension\Plugin\Field\FieldType;
use Drupal;
use Drupal\dimension\Plugin\Field\Basic;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\DecimalItem;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TypedData\DataDefinition;
abstract class Dimension extends DecimalItem implements Basic {
protected static function _defaultStorageSettings($fields) : array {
$settings = [
'value_precision' => 10,
'value_scale' => 2,
];
foreach ($fields as $key => $label) {
$settings[$key . '_precision'] = 10;
$settings[$key . '_scale'] = 2;
}
return $settings;
}
protected static function _defaultFieldSettings($fields) : array {
$settings = [
'value' => [
'factor' => 1,
'min' => '',
'max' => '',
'prefix' => '',
'suffix' => '',
],
];
foreach ($fields as $key => $label) {
$settings[$key] = [
'factor' => 1,
'min' => '',
'max' => '',
'prefix' => '',
'suffix' => '',
];
}
return $settings;
}
protected static function _propertyDefinitions($fields) : array {
$properties = [];
$properties['value'] = DataDefinition::create('string')
->setLabel(t('Value'))
->setRequired(TRUE);
foreach ($fields as $key => $label) {
$properties[$key] = DataDefinition::create('string')
->setLabel($label)
->setRequired(TRUE);
}
return $properties;
}
protected static function _schema(FieldStorageDefinitionInterface $field_definition, $fields) : array {
$settings = $field_definition
->getSettings();
$schema = [
'columns' => [
'value' => [
'type' => 'numeric',
'precision' => $settings['value_precision'],
'scale' => $settings['value_scale'],
],
],
];
foreach ($fields as $key => $label) {
$schema['columns'][$key] = [
'type' => 'numeric',
'precision' => $settings[$key . '_precision'],
'scale' => $settings[$key . '_scale'],
];
}
return $schema;
}
private function _storageSettings(&$element, $key, $label, $has_data, $settings) : void {
$range = range(10, 32);
$element[$key . '_precision'] = [
'#type' => 'select',
'#title' => $this
->t('%label precision', [
'%label' => $label,
]),
'#options' => array_combine($range, $range),
'#default_value' => $settings[$key . '_precision'],
'#description' => $this
->t('The total number of digits to store in the database, including those to the right of the decimal.'),
'#disabled' => $has_data,
];
$range = range(0, 10);
$element[$key . '_scale'] = [
'#type' => 'select',
'#title' => $this
->t('%label scale', [
'%label' => $label,
]),
'#options' => array_combine($range, $range),
'#default_value' => $settings[$key . '_scale'],
'#description' => $this
->t('The number of digits to the right of the decimal.'),
'#disabled' => $has_data,
];
}
public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) : array {
$settings = $this
->getSettings();
$element = [];
foreach ($this
->fields() as $key => $label) {
$this
->_storageSettings($element, $key, $label, $has_data, $settings);
}
$this
->_storageSettings($element, 'value', $this
->t('Full dimension'), $has_data, $settings);
return $element;
}
private function _fieldSettings(&$element, $key, $label, $hide_constraints = FALSE) : void {
$settings = $this
->getSetting($key);
$element[$key] = [
'#type' => 'fieldset',
'#title' => $label,
];
$element[$key]['factor'] = [
'#type' => 'number',
'#title' => $this
->t('Factor'),
'#default_value' => $settings['factor'],
'#step' => 0.1 ** 2,
'#required' => TRUE,
'#description' => $this
->t('A factor to multiply the @label with when calculating the @field', [
'@label' => $label,
'@field' => $this
->getFieldDefinition()
->getLabel(),
]),
'#access' => !$hide_constraints,
];
$element[$key]['min'] = [
'#type' => 'number',
'#title' => $this
->t('Minimum'),
'#default_value' => $settings['min'],
'#step' => 0.1 ** $this
->getSetting($key . '_scale'),
'#description' => $this
->t('The minimum value that should be allowed in this field. Leave blank for no minimum.'),
'#access' => !$hide_constraints,
];
$element[$key]['max'] = [
'#type' => 'number',
'#title' => $this
->t('Maximum'),
'#default_value' => $settings['max'],
'#step' => 0.1 ** $this
->getSetting($key . '_scale'),
'#description' => $this
->t('The maximum value that should be allowed in this field. Leave blank for no maximum.'),
'#access' => !$hide_constraints,
];
$element[$key]['prefix'] = [
'#type' => 'textfield',
'#title' => $this
->t('Prefix'),
'#default_value' => $settings['prefix'],
'#size' => 60,
'#description' => $this
->t("Define a string that should be prefixed to the value, like 'cm ' or 'inch '. Leave blank for none. Separate singular and plural values with a pipe ('inch|inches')."),
];
$element[$key]['suffix'] = [
'#type' => 'textfield',
'#title' => $this
->t('Suffix'),
'#default_value' => $settings['suffix'],
'#size' => 60,
'#description' => $this
->t("Define a string that should be suffixed to the value, like ' mm', ' inch'. Leave blank for none. Separate singular and plural values with a pipe ('inch|inches')."),
];
}
public function fieldSettingsForm(array $form, FormStateInterface $form_state) : array {
$element = [];
foreach ($this
->fields() as $key => $label) {
$this
->_fieldSettings($element, $key, $label);
}
$this
->_fieldSettings($element, 'value', $this
->t('Full dimension'), TRUE);
return $element;
}
public function getConstraints() : array {
$constraint_manager = Drupal::typedDataManager()
->getValidationConstraintManager();
$constraints = [];
foreach ($this->definition
->getConstraints() as $name => $options) {
$constraints[] = $constraint_manager
->create($name, $options);
}
foreach ($this
->fields() as $key => $label) {
$settings = $this
->getSetting($key);
$constraints[] = $constraint_manager
->create('ComplexData', [
$key => [
'Regex' => [
'pattern' => '/^[+-]?((\\d+(\\.\\d*)?)|(\\.\\d+))$/i',
],
],
]);
if (!empty($settings['min'])) {
$min = $settings['min'];
$constraints[] = $constraint_manager
->create('ComplexData', [
$key => [
'Range' => [
'min' => $min,
'minMessage' => $this
->t('%name: the value may be no less than %min.', [
'%name' => $label,
'%min' => $min,
]),
],
],
]);
}
if (!empty($settings['max'])) {
$max = $settings['max'];
$constraints[] = $constraint_manager
->create('ComplexData', [
$key => [
'Range' => [
'max' => $max,
'maxMessage' => $this
->t('%name: the value may be no greater than %max.', [
'%name' => $label,
'%max' => $max,
]),
],
],
]);
}
}
return $constraints;
}
public function preSave() : void {
$values = [];
foreach ($this
->fields() as $key => $label) {
$values[$key] = $this->{$key};
$this->{$key} = round($this->{$key}, $this
->getSetting($key . '_scale'));
}
$this->value = $this
->calculate($values);
}
public function isEmpty() : bool {
foreach ($this
->fields() as $key => $label) {
if (empty($this->{$key}) && (string) $this->{$key} !== '0') {
return TRUE;
}
}
return FALSE;
}
public function calculate($values) {
$value = 1;
foreach ($this
->fields() as $key => $label) {
$settings = $this
->getSetting($key);
$values[$key] = round($values[$key], $this
->getSetting($key . '_scale'));
$value *= $values[$key] * $settings['factor'];
}
return round($value, $this
->getSetting('value_scale'));
}
}