datafield-1.x-dev/src/Plugin/DataType/DataFieldUriData.php
src/Plugin/DataType/DataFieldUriData.php
<?php
namespace Drupal\datafield\Plugin\DataType;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\TypedData\EntityDataDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\Attribute\DataType;
use Drupal\Core\TypedData\ComplexDataInterface;
use Drupal\Core\TypedData\Exception\MissingDataException;
use Drupal\Core\TypedData\TypedData;
use Drupal\Core\Url;
/**
* Defines the "uri" data type.
*
* Instances of this class wrap entity objects and allow to deal with entities
* based upon the Typed Data API.
*
* In addition to the "entity" data type, this exposes derived
* "entity:$entity_type" and "entity:$entity_type:$bundle" data types.
*/
#[DataType(
id: "uri_datafield",
label: new TranslatableMarkup("Uri Data field"),
description: new TranslatableMarkup("All kind of entities, e.g. nodes, comments or users."),
definition_class: EntityDataDefinition::class,
)]
class DataFieldUriData extends TypedData implements \IteratorAggregate, ComplexDataInterface {
/**
* The wrapped entity object.
*
* @var \Drupal\Core\Entity\EntityInterface|null
*/
protected $entity;
/**
* Creates an instance wrapping the given entity.
*
* @param \Drupal\Core\Entity\EntityInterface|null $entity
* The entity object to wrap.
*
* @return static
*/
public static function createFromEntity(EntityInterface $entity) {
$definition = EntityDataDefinition::create()
->setEntityTypeId($entity->getEntityTypeId())
->setBundles([$entity->bundle()]);
$instance = new self($definition);
$instance->setValue($entity);
return $instance;
}
/**
* {@inheritdoc}
*/
public function getValue() {
$value = $this->loadEntity();
if (!empty($value['url'])) {
return $value['url'];
}
if (!empty($value['id'])) {
return $value['id'];
}
return $value;
}
/**
* {@inheritDoc}
*/
public function loadEntity($entity = NULL) {
$entity = $this->entity ?? $entity;
$entityType = 'node';
if (is_string($this->entity) && str_starts_with($this->entity, '/')) {
$url = Url::fromUri('internal:' . $this->entity);
if ($url->isRouted()) {
$params = $url->getRouteParameters();
$entityType = key($params);
$this->entity = $params[$entityType];
}
}
if (is_numeric($this->entity)) {
$entity = \Drupal::entityTypeManager()
->getStorage($entityType)
->load($this->entity);
}
if (is_object($entity)) {
$label_field = $entity->getEntityType()->getKey('label');
$title = $label_field ? $entity->get($label_field)?->value : '';
if (empty($title) && method_exists($entity, 'getDisplayName')) {
$title = $entity->getDisplayName();
}
return [
'id' => $entity->id(),
'uuid' => $entity->uuid(),
'url' => $entity->toUrl()->toString(),
'title' => $title,
'entity_type' => $entityType,
'bundle' => $entity->bundle(),
];
}
elseif (is_null($entity)) {
return NULL;
}
return ['url' => $entity];
}
/**
* {@inheritdoc}
*/
public function setValue($entity, $notify = TRUE) {
$this->entity = $entity;
// Notify the parent of any changes.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
}
/**
* {@inheritdoc}
*/
public function get($property_name) {
$this->loadEntity();
if (is_string($this->entity)) {
return $this->entity;
}
// This will throw an exception for unknown fields.
return $this->entity->get($property_name);
}
/**
* {@inheritdoc}
*/
public function set($property_name, $value, $notify = TRUE) {
if (!isset($this->entity)) {
throw new MissingDataException("Unable to set property $property_name as no entity has been provided.");
}
if (!$this->entity instanceof FieldableEntityInterface) {
throw new \InvalidArgumentException("Unable to set unknown property $property_name.");
}
// This will throw an exception for unknown fields.
$this->entity->set($property_name, $value, $notify);
return $this;
}
/**
* {@inheritdoc}
*/
public function getProperties($include_computed = FALSE) {
if ($this->entity == NULL) {
return [];
}
if (!isset($this->entity)) {
throw new MissingDataException('Unable to get properties as no entity has been provided.');
}
if (!$this->entity instanceof FieldableEntityInterface) {
return [];
}
return $this->entity->getFields($include_computed);
}
/**
* {@inheritdoc}
*/
public function toArray() {
if (!isset($this->entity)) {
throw new MissingDataException('Unable to get property values as no entity has been provided.');
}
return $this->entity->toArray();
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
return !isset($this->entity);
}
/**
* {@inheritdoc}
*/
public function onChange($property_name) {
if (isset($this->entity) && $this->entity instanceof FieldableEntityInterface) {
// Let the entity know of any changes.
$this->entity->onChange($property_name);
}
}
/**
* {@inheritdoc}
*/
public function getString() {
return isset($this->entity) ? $this->entity->label() : '';
}
/**
* {@inheritdoc}
*/
public function applyDefaultValue($notify = TRUE) {
// Apply the default value of all properties.
foreach ($this->getProperties() as $property) {
$property->applyDefaultValue(FALSE);
}
return $this;
}
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function getIterator() {
return $this->entity instanceof \IteratorAggregate ? $this->entity->getIterator() : new \ArrayIterator([]);
}
/**
* Returns the wrapped entity object.
*
* @return \Drupal\Core\Entity\EntityInterface
* The wrapped entity object. If the entity is translatable and a specific
* translation is required, always request it by calling ::getTranslation()
* or ::getUntranslated() as the language of the returned object is not
* defined.
*/
public function getEntity() {
return $this->entity;
}
}
