Skip to content
Snippets Groups Projects
Commit 93f73d1f authored by Mikael Meulle's avatar Mikael Meulle
Browse files

Merge branch '3514270-field-item-to-source' into '2.0.x'

Draft: Resolve #3514270 "Field item to source"

See merge request !366
parents b2216dcb 8fe3eac4
Branches 1.0.x 1.1.x
Tags 1.1.1
No related merge requests found
Pipeline #467591 failed
<?php
declare(strict_types=1);
namespace Drupal\ui_patterns\Attribute;
use Drupal\Component\Plugin\Attribute\Plugin;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Defines a Field item source attribute.
*
* Plugin Namespace: Plugin\UiPatterns\FieldItemSource.
*
* @ingroup ui_patterns
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class FieldItemSource extends Plugin {
/**
* Constructs a source attribute object.
*
* @param string $id
* A unique identifier for the source plugin.
* @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
* Translatable label for the source plugin.
* @param ?\Drupal\Core\StringTranslation\TranslatableMarkup $description
* = NULL
* Translatable description for the source plugin.
* @param ?string $prop_type
* Prop type for this field item source.
*/
public function __construct(
public readonly string $id,
public readonly TranslatableMarkup $label,
public readonly ?TranslatableMarkup $description = NULL,
public readonly ?string $prop_type = NULL,
) {}
}
<?php
declare(strict_types=1);
namespace Drupal\ui_patterns;
use Drupal\Core\Field\FieldItemInterface;
/**
* Interface for Field item source plugins.
*/
interface FieldItemSourceInterface {
/**
*
*/
public function isApplicable(string $entity_type_id, string $bundle, string $field_name, array $field_storage_metadata, array $field_metadata): bool;
/**
*
*/
public function getPropValue(FieldItemInterface $field_item): mixed;
}
<?php
namespace Drupal\ui_patterns;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\ui_patterns\Attribute\FieldItemSource;
/**
* Provides a Field item source plugin manager.
*
* @see plugin_api
*/
class FieldItemSourcePluginManager extends DefaultPluginManager implements ContextAwarePluginManagerInterface, ContextMatcherPluginManagerInterface {
use \Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
use ContextMatcherPluginManagerTrait;
/**
* Constructs a new class instance.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
parent::__construct(
'Plugin/UiPatterns/FieldItemSource',
$namespaces,
$module_handler,
FieldItemSourceInterface::class,
FieldItemSource::class
);
$this->alterInfo('ui_patterns_field_item_source_info');
$this->setCacheBackend($cache_backend, 'ui_patterns_field_item_source_info');
}
/**
*
*/
public function getDefinitions() : array {
$definitions = parent::getDefinitions();
return $definitions;
}
}
<?php
namespace Drupal\ui_patterns\Plugin\Derivative;
use Drupal\Component\Plugin\PluginBase;
use Drupal\ui_patterns\FieldItemSourceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides Field item sources for every field.
*/
class FieldItemSourceDeriver extends EntityFieldSourceDeriverBase {
/**
* The ui patterns field item source plugin manager.
*
* @var \Drupal\ui_patterns\FieldItemSourcePluginManager
*/
protected $fieldItemSourcePluginManager = NULL;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
$plugin = parent::create($container, $base_plugin_id);
$plugin->fieldItemSourcePluginManager = $container->get('plugin.manager.ui_patterns_field_item_source');
return $plugin;
}
/**
* {@inheritdoc}
*/
protected function getDerivativeDefinitionsForEntityBundleField(string $entity_type_id, string $bundle, string $field_name, array $base_plugin_derivative): void {
$pluginsDefinitions = $this->fieldItemSourcePluginManager->getDefinitions();
$field_metadata = $this->entityFieldsMetadata[$entity_type_id]["bundles"][$bundle]["fields"][$field_name];
$storage_metadata = $this->entityFieldsMetadata[$entity_type_id]["field_storages"][$field_name] ?? [];
foreach ($pluginsDefinitions as $plugin_id => $definition) {
$plugin = $this->fieldItemSourcePluginManager->createInstance($plugin_id);
if (!$plugin instanceof FieldItemSourceInterface) {
continue;
}
$compatible_prop_type = $definition["prop_type"] ?? '';
if (!$compatible_prop_type || !$plugin->isApplicable($entity_type_id, $bundle, $field_name, $storage_metadata, $field_metadata)) {
continue;
}
$id = implode(PluginBase::DERIVATIVE_SEPARATOR, [
$entity_type_id,
$bundle,
$field_name,
$definition["id"],
]);
$this->derivatives[$id] = array_merge(
$base_plugin_derivative,
[
"id" => $id,
"label" => empty($definition["label"]) ? $definition["id"] : $definition["label"],
"description" => empty($definition["description"]) ? "" : $definition["description"],
"metadata" => array_merge($base_plugin_derivative["metadata"], [
'field_item_source' => $plugin_id,
]),
"context_requirements" => array_merge($base_plugin_derivative["context_requirements"], ["field_granularity:item"]),
"tags" => array_merge($base_plugin_derivative["tags"], ["field_item_source"]),
"prop_types" => [$compatible_prop_type],
]);
}
}
/**
* {@inheritdoc}
*/
protected function getDerivativeDefinitionsForEntityStorageField(string $entity_type_id, string $field_name, array $base_plugin_derivative): void {
/* $id = implode(PluginBase::DERIVATIVE_SEPARATOR, [
$entity_type_id,
"",
$field_name,
]);
$this->derivatives[$id] = array_merge(
$base_plugin_derivative,
[
"id" => $id,
"label" => $this->t("Field formatter"),
"description" => $this->t("Output of a field formatter."),
"metadata" => array_merge($base_plugin_derivative["metadata"], [
'field_formatter' => TRUE,
]),
"context_requirements" => array_merge($base_plugin_derivative["context_requirements"], ["field_granularity:item"]),
"tags" => array_merge($base_plugin_derivative["tags"], ["field_formatter"]),
"prop_types" => ["slot"],
]);
*/
}
}
<?php
namespace Drupal\ui_patterns\Plugin\UiPatterns\FieldItemSource;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\ui_patterns\Attribute\FieldItemSource;
use Drupal\ui_patterns\FieldItemSourceInterface;
use Drupal\Core\Field\FieldItemInterface;
/**
* Provides a field item source for link items to extract attributes.
*/
#[FieldItemSource(
id: 'link_attributes',
label: new TranslatableMarkup('Link Attributes'),
description: new TranslatableMarkup('convert link item attribtues to an attribute prop type'),
prop_type: 'attributes',
)]
class LinkAttributes implements FieldItemSourceInterface {
/**
* {@inheritdoc}
*/
public function isApplicable(string $entity_type_id, string $bundle, string $field_name, array $field_storage_metadata, array $field_metadata): bool {
return ($field_storage_metadata["metadata"]['type'] ?? '') === 'link';
}
/**
* {@inheritdoc}
*/
public function getPropValue(FieldItemInterface $field_item): mixed {
if ($field_item->isEmpty()) {
return NULL;
}
/** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $field_item */
$url = $field_item->getUrl();
return $url->getOptions()["attributes"] ?? [];
}
}
<?php
declare(strict_types=1);
namespace Drupal\ui_patterns\Plugin\UiPatterns\Source;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\ui_patterns\Attribute\Source;
use Drupal\ui_patterns\Plugin\Derivative\FieldItemSourceDeriver;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the prop source.
*/
#[Source(
id: 'field_item_source',
label: new TranslatableMarkup('Field Item source'),
description: new TranslatableMarkup('Field item converted to source.'),
deriver: FieldItemSourceDeriver::class
)]
class FieldItemSource extends FieldValueSourceBase {
/**
* @var \Drupal\ui_patterns\FieldItemSourcePluginManager
*/
protected $fieldItemSourcePluginManager;
/**
* {@inheritdoc}
*/
public static function create(
ContainerInterface $container,
array $configuration,
$plugin_id,
$plugin_definition,
) {
// We keep the same constructor as SourcePluginBase.
$instance = parent::create(
$container,
$configuration,
$plugin_id,
$plugin_definition
);
// Defined in parent class FieldSourceBase.
$instance->fieldItemSourcePluginManager = $container->get('plugin.manager.ui_patterns_field_item_source');
return $instance;
}
/**
* {@inheritdoc}
*/
public function getPropValue(): mixed {
$items = $this->getEntityFieldItemList();
$delta = (isset($this->context['ui_patterns:field:index'])) ? $this->getContextValue('ui_patterns:field:index') : 0;
$field_item_source = $this->getCustomPluginMetadata('field_item_source');
if (empty($field_item_source) || empty($items)) {
return NULL;
}
/** @var \Drupal\Core\Field\FieldItemInterface $field_item_at_delta */
$field_item_at_delta = $items->get($delta);
if (!$field_item_at_delta) {
return NULL;
}
/** @var \Drupal\ui_patterns\FieldItemSourceInterface $fieldItemSourcePlugin */
$fieldItemSourcePlugin = $this->fieldItemSourcePluginManager->createInstance($field_item_source, []);
return $fieldItemSourcePlugin->getPropValue($field_item_at_delta);
}
}
...@@ -39,6 +39,9 @@ services: ...@@ -39,6 +39,9 @@ services:
parent: default_plugin_manager parent: default_plugin_manager
arguments: arguments:
- "@entity_type.manager" - "@entity_type.manager"
plugin.manager.ui_patterns_field_item_source:
class: Drupal\ui_patterns\FieldItemSourcePluginManager
parent: default_plugin_manager
# Render elements management. # Render elements management.
ui_patterns.component_element_builder: ui_patterns.component_element_builder:
class: Drupal\ui_patterns\Element\ComponentElementBuilder class: Drupal\ui_patterns\Element\ComponentElementBuilder
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment