datafield-1.x-dev/src/Plugin/Field/FieldFormatter/Base.php
src/Plugin/Field/FieldFormatter/Base.php
<?php
namespace Drupal\datafield\Plugin\Field\FieldFormatter;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\datafield\Plugin\DataFieldFormatterPluginManager;
use Drupal\datafield\Plugin\DataFieldTypePluginManager;
use Drupal\datafield\Plugin\Field\FieldType\DataFieldItem;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Base class for data field formatters.
*/
abstract class Base extends FormatterBase {
/**
* Constructs a FormatterBase object.
*
* @param string $plugin_id
* The plugin_id for the formatter.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The definition of the field to which the formatter is associated.
* @param array $settings
* The formatter settings.
* @param string $label
* The formatter label display setting.
* @param string $view_mode
* The view mode.
* @param array $third_party_settings
* Any third party settings.
* @param \Drupal\datafield\Plugin\DataFieldTypePluginManager $pluginType
* Plugin data type service.
* @param \Drupal\datafield\Plugin\DataFieldFormatterPluginManager $pluginFormatter
* Plugin data formatter service.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, protected DataFieldTypePluginManager $pluginType, protected DataFieldFormatterPluginManager $pluginFormatter) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id, $plugin_definition, $configuration['field_definition'],
$configuration['settings'], $configuration['label'],
$configuration['view_mode'], $configuration['third_party_settings'],
$container->get('plugin.manager.data_field.type'),
$container->get('plugin.manager.data_field.formatter'),
);
}
/**
* {@inheritdoc}
*/
public static function defaultSettings(): array {
$default = [
'formatter_settings' => [],
'ajax' => FALSE,
'custom_class' => '',
'line_operations' => FALSE,
'form_format_table' => FALSE,
];
return $default + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state): array {
$settings = $this->getSetting('formatter_settings');
$fieldSettings = $this->getFieldSettings();
$types = DataFieldItem::subfieldTypes();
$subfields = $this->getFieldSetting('columns');
$field_name = $this->fieldDefinition->getName();
if (!empty($settings) && count($subfields) == count($settings)) {
uasort($settings, [
'Drupal\Component\Utility\SortArray',
'sortByWeightElement',
]);
$subfields = $settings;
}
$element = [
'ajax' => [
'#title' => $this->t('Load data with ajax'),
'#description' => $this->t('Use ajax to load big data'),
'#type' => 'checkbox',
'#default_value' => $this->getSetting('ajax'),
],
'custom_class' => [
'#title' => $this->t('Set table class'),
'#type' => 'textfield',
'#default_value' => $this->getSetting('custom_class'),
],
'line_operations' => [
'#title' => $this->t('Show operations'),
'#type' => 'checkbox',
'#default_value' => $this->getSetting('line_operations'),
],
'form_format_table' => [
'#title' => $this->t('Format table in add / edit form'),
'#type' => 'checkbox',
'#default_value' => $this->getSetting('form_format_table'),
],
];
$formatterTypes = $this->pluginType->getDefinitions();
$default_formatter = [];
foreach ($formatterTypes as $formatter_type) {
$default_formatter[$formatter_type['id']] = $formatter_type['default_formatter'];
}
$formatter_types = $this->pluginFormatter->getDefinitions();
$formatterList = $this->pluginFormatter->getDefinitions();
foreach ($formatter_types as $formatter_type) {
foreach ($formatter_type['field_types'] as $type) {
$option_formatter[$type][$formatter_type['id']] = $formatter_type['label'];
}
}
// General settings.
foreach (array_keys($subfields) as $subfield) {
$item = $fieldSettings["columns"][$subfield];
$type = $item['type'];
$title = $item['name'] . ' - ' . $types[$type];
$formatter_type = $settings[$subfield]['format_type'] ?? $default_formatter[$type];
if (in_array($type, ['datetime_iso8601', 'date'])) {
switch ($item["datetime_type"]) {
case 'time':
case 'week':
case 'month':
if (empty($settings[$subfield]["format_type"])) {
$formatter_type = $default_formatter["string"];
}
$type = 'string';
break;
case 'year':
if (empty($settings[$subfield]["format_type"])) {
$formatter_type = $default_formatter["integer"];
}
$type = 'integer';
break;
}
}
$field_settings = $this->getFieldSetting('field_settings');
if (!empty($field_settings[$subfield]['list'])) {
$title .= ' (' . $this->t('list') . ')';
}
$form['#storage_settings'] = $item;
$form['#field_settings'] = $field_settings[$subfield] ?? [];
$form['#field_name'] = $field_name;
$form['#settings'] = $settings[$subfield] ?? [];
$form['#machine_name'] = $subfield;
$formatter_settings = [
'hidden' => [
'#type' => 'checkbox',
'#title' => $this->t('Hidden'),
'#default_value' => $settings[$subfield]['hidden'] ?? FALSE,
],
'show_label' => [
'#type' => 'checkbox',
'#title' => $this->t('Show label'),
'#default_value' => $settings[$subfield]['show_label'] ?? FALSE,
],
];
if (!empty($formatterList[$formatter_type])) {
$plugin = $this->pluginFormatter->createInstance($formatter_type);
$formatter_settings += $plugin->settingsForm($form, $form_state) ?? [];
}
$options = $option_formatter[$type] ?? [];
$element['formatter_settings'][$subfield] = [
'#title' => $title,
'#type' => 'details',
'format_type' => [
'#type' => 'select',
'#title' => $this->t('Formatter type'),
'#description' => $this->t('Save and back again to get options.'),
'#options' => $options,
'#empty_option' => $this->t('- Select -'),
'#default_value' => $formatter_type,
],
'weight' => [
'#type' => 'weight',
'#title' => $this->t('Weight for fields'),
'#default_value' => $settings[$subfield]['weight'] ?? 0,
'#weight' => 20,
],
] + $formatter_settings;
}
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary(): array {
$settings = $this->getSetting('formatter_settings');
$fieldSettings = $this->getFieldSettings();
$subfield_types = DataFieldItem::subfieldTypes();
$formatterTypes = $this->pluginType->getDefinitions();
$formatterList = $this->pluginFormatter->getDefinitions();
$default_formatter = [];
foreach ($formatterTypes as $formatter_type) {
$default_formatter[$formatter_type['id']] = $formatter_type['default_formatter'];
}
$summary = [];
foreach ($fieldSettings["columns"] as $subfield => $item) {
$subfield_type = $item['type'];
if (empty($settings[$subfield]) || empty($fieldSettings["field_settings"])) {
continue;
}
$formatter_type = $settings[$subfield]['format_type'] ?: $default_formatter[$subfield_type];
if (empty($formatterList[$formatter_type])) {
continue;
}
$plugin = $this->pluginFormatter->createInstance($formatter_type);
if (!empty($fieldSettings["field_settings"][$subfield]["label"])) {
$summary[] = new FormattableMarkup('<b>@subfield - @subfield_type@list</b>', [
'@subfield' => $fieldSettings["field_settings"][$subfield]["label"],
'@subfield_type' => strtolower($subfield_types[$subfield_type]),
'@list' => !empty($fieldSettings["field_settings"][$subfield]["list"]) ? ' (' . $this->t('list') . ')' : '',
]);
}
if (isset($settings[$subfield]['hidden'])) {
$summary[] = $this->t('Hidden: @value', ['@value' => $settings[$subfield]['hidden'] ? $this->t('yes') : $this->t('no')]);
}
if (method_exists($plugin, 'settingsSummary')) {
$settingsSummary = $settings[$subfield];
if (!empty($fieldSettings['field_settings'][$subfield])) {
$settingsSummary += $fieldSettings['field_settings'][$subfield];
}
$summary = [...$summary, ...$plugin->settingsSummary($settingsSummary)];
}
}
return $summary;
}
/**
* {@inheritdoc}
*/
public function view(FieldItemListInterface $items, $langcode = NULL): array {
$elements = [];
$settings = $this->getSettings();
if (!$items->isEmpty()) {
// A field may appear multiple times in a single view. Since items are
// passed by reference we need to ensure they are processed only once.
$items = clone $items;
$this->prepareItems($items, $langcode);
$elements = parent::view($items, $langcode);
}
elseif (!empty($settings['line_operations'])) {
$elements = parent::view($items, $langcode);
}
return $elements;
}
/**
* Prepare field items.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* List of field items.
* @param string $langcode
* Language code.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityMalformedException|\Drupal\Component\Plugin\Exception\PluginException
*/
protected function prepareItems(FieldItemListInterface $items, $langcode = NULL): void {
$fieldSettings = $this->getFieldSettings();
$settings = $this->getSettings();
$setting = $settings['formatter_settings'];
$formatterSettings = $this->getSetting('formatter_settings');
$columns = $fieldSettings['columns'];
$subfields = !empty($settings['formatter_settings']) ? $settings['formatter_settings'] : $columns;
uasort($subfields, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
$formatterTypes = $this->pluginType->getDefinitions();
$default_formatter = [];
foreach ($formatterTypes as $formatter_type) {
$default_formatter[$formatter_type['id']] = $formatter_type['default_formatter'];
}
foreach ($items as $delta => $item) {
foreach (array_keys($subfields) as $subfield) {
if (empty($columns[$subfield]) || !empty($setting[$subfield]["hidden"])) {
continue;
}
$field_setting = $fieldSettings["field_settings"][$subfield];
$value_original = $item->{$subfield};
if (!empty($field_setting['list']) && !empty($field_setting['allowed_values'])) {
// @todo Remove the fallback in 5.x.
$display_key = $setting['key'] ?? FALSE;
if (!$display_key) {
// Replace the value with its label if possible.
$item->{$subfield} = $field_setting['allowed_values'][$item->{$subfield}] ?? NULL;
}
}
$formatter_type = $default_formatter[$columns[$subfield]['type']];
$plugin = $this->pluginFormatter->createInstance($setting[$subfield]['format_type'] ?? $formatter_type);
$value = $item->{$subfield};
$viewItem = (object) [
'value' => $value['value'] ?? $value,
'value_original' => $value_original,
'field_setting' => $field_setting,
'settings' => $formatterSettings[$subfield] ?? [],
'storage' => $fieldSettings["columns"][$subfield],
'entity' => $items->getEntity(),
'field_name' => $items->getFieldDefinition()->getName(),
'machine_name' => $subfield,
];
$item->{$subfield} = $plugin->viewElements($viewItem, $langcode);
}
$items[$delta] = $item;
}
}
/**
* Check permission Operation.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to check ownership.
* @param string $fieldName
* The field name for permission check.
*
* @return bool
* TRUE if the user has the required permission, FALSE otherwise.
*/
public static function checkPermissionOperation($entity, $fieldName): bool {
$user = \Drupal::currentUser();
// Check administrator role first for quick exit.
if (in_array('administrator', $user->getRoles())) {
return TRUE;
}
// Define permissions to check.
$permissions = [
'bypass node access',
'administer nodes',
'create ' . $fieldName,
'edit ' . $fieldName,
'edit own ' . $fieldName,
];
// Check general permissions.
foreach ($permissions as $permission) {
if ($user->hasPermission($permission)) {
return TRUE;
}
}
// Check ownership if entity is not a user entity.
if ($entity->getEntityTypeId() !== 'user' && method_exists($entity, 'getOwnerId')) {
$uid = $entity->getOwnerId();
if ($uid && $uid == $user->id() && $user->hasPermission("edit own $fieldName")) {
return TRUE;
}
}
return FALSE;
}
}
