ww_publish-8.x-1.x-dev/src/Field.php
src/Field.php
<?php
namespace Drupal\ww_publish;
use Drupal\Core\Field\FieldDefinitionInterface;
class Field {
use MediaFieldTrait;
use FieldTrait;
/**
* Configuration of the field.
*
* @var \Drupal\Core\Field\FieldDefinitionInterface
*/
private $fieldConfig;
/**
* WoodWing Studio identifier.
*
* @var string
*/
private $contentStationIdentifier;
/**
* The SNS message.
*
* @var \Drupal\ww_publish\Message
*/
protected $message;
/**
* Article Data.
*
* @var Object
*/
private $articleData;
/**
* Configuration of the ww_publish module.
*
* @var \Drupal\Core\Config\Config
*/
private $config;
/**
* A logger instance.
*
* @var \Psr\Log\LoggerInterface
*/
private $logger;
/**
* Constructor.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_config
* Field configuration.
* @param string $content_station_identifier
* WoodWing Studio identifier.
* @param \Drupal\ww_publish\Message $message
* Article metadata.
* @param Object $article_data
* Article data.
* @param array $prepared_files
* Prepared files.
* @param string $article_id_field
* WoodWing Studio article ID field.
* @param \Drupal\Core\Config\Config $config
* Configuration of the ww_publish module.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
*/
public function __construct(FieldDefinitionInterface $field_config, $content_station_identifier, Message $message, $config, $logger) {
$this->message = $message;
$this->fieldConfig = $field_config;
$this->contentStationIdentifier = $content_station_identifier;
$this->articleData = $message->getArticleData();
$this->config = $config;
$this->logger = $logger;
}
/**
* Get article data.
*
* @param array $messagesField
* Error messages field.
*
* @return array
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function getArticleData(&$messagesField = NULL): ?array {
$articleData = [];
$fieldType = $this->fieldConfig->getType();
$contentStationIdentifiers = explode('|', $this->contentStationIdentifier);
switch ($fieldType) {
case 'text_with_summary':
// Get field value.
$fieldValue = $this->getComponentContent($contentStationIdentifiers[0]);
if (is_array($fieldValue)) {
$articleData['value'] = implode(' ', $fieldValue);
} else {
$articleData['value'] = $fieldValue;
}
// Add summary, if defined in WoodWing Studio identifier, e.g.: 'body|intro'.
$noSummary = TRUE;
if (count($contentStationIdentifiers) === 2) {
$summary = $this->getComponentContent($contentStationIdentifiers[1]);
if (is_array($summary)) {
$articleData['summary'] = implode(' ', $summary);
} else {
$articleData['summary'] = $summary;
}
$noSummary = $articleData['summary'] === FALSE;
}
if ($articleData['value'] === FALSE && $noSummary) {
$articleData = [];
} else {
$articleData['format'] = $this->getTextFormat($this->fieldConfig);
}
break;
case 'entity_reference':
if ($this->config->get('debug_mode'))
$this->logger->debug('Entity reference!');
if ($this->config->get('debug_mode'))
$this->logger->debug('Identifiers: <pre><code>@identifiers</code></pre>', ['@identifiers' => print_r($contentStationIdentifiers, TRUE)]);
$media_bundle = $this->getMediaTargetBundle($this->fieldConfig);
if ($media_bundle && count($contentStationIdentifiers) > 1) {
$component = $this->getComponent($contentStationIdentifiers[0]);
if ($this->config->get('debug_mode'))
$this->logger->debug('Component: <pre><code>@component</code></pre>', ['@component' => print_r($component, TRUE)]);
if ($component && !empty($component->content->image)) {
$referenceId = $this->createMediaImage($media_bundle, $component->content);
if ($this->config->get('debug_mode'))
$this->logger->debug('Reference ID: ' . $referenceId);
$articleData['target_id'] = $referenceId;
}
}
// Attempt to look up the reference from the handler.
if ($referenceId = $this->getReferenceFromHandler($contentStationIdentifiers)) {
if ($this->config->get('debug_mode'))
$this->logger->debug('Reference ID: ' . $referenceId);
$articleData['target_id'] = $referenceId;
}
break;
default:
$wwComponent = $this->getComponent($contentStationIdentifiers[0]);
$content = [];
if ($wwComponent && property_exists($wwComponent, 'content')) {
foreach ($wwComponent->content as $content_key => $component_content) {
$content[$content_key] = '';
if (\is_array($component_content)) {
foreach ($component_content as $text) {
$content[$content_key] .= $this->getAtributeContent($text, (bool) $this->fieldConfig->getFieldStorageDefinition()->getPropertyDefinition('format'));
}
}
else {
$content[$content_key] = $component_content;
}
}
}
$content = \array_filter($content);
if (!empty($content)) {
// Apply a template on the content.
/** @var \Drupal\ww_publish\Template $template */
$template = \Drupal::service('ww_publish.template');
if ($template->exist($contentStationIdentifiers[0], 'component')) {
$content = $template->apply($contentStationIdentifiers[0], 'component', $content);
}
else {
// No template, pick either the specified or first content
// component.
if (count($contentStationIdentifiers) === 2) {
$content = $content[$contentStationIdentifiers[1]] ?? '';
}
else {
$content = reset($content);
}
}
$content = $this->shortenValueToFieldMaxLength($content, $this->fieldConfig, $messagesField);
// Create a new paragraph.
if (\in_array($fieldType, ['string', 'string_long'])) {
$articleData = [
'value' => strip_tags($content)
];
}
else {
$articleData = [
'value' => $content,
'format' => $this->getTextFormat($this->fieldConfig),
];
}
}
elseif ($this->fieldConfig->isRequired()) {
$message = 'The component with identifier @station_identifier can not be saved as a string in the field @field_name.';
$this->logger->error($message, ['@station_identifier' => $this->contentStationIdentifier, '@field_name' => $this->fieldConfig->getName()]);
$messagesField[]['value'] = t($message, ['@station_identifier' => $this->contentStationIdentifier, '@field_name' => $this->fieldConfig->getName()]);
}
break;
}
if (empty($articleData)) {
return NULL;
} else {
return $articleData;
}
}
/**
* Get the component content.
*
* @param string $contentStationIdentifier
* WoodWing Studio identifier.
* @param string $contentProperty
* Property in the content object.
* @param string $textProperty
* Property in the object in the text array.
*
* @return string|array|bool
*/
private function getComponentContent($contentStationIdentifier, $contentProperty = 'text', $textProperty = 'insert') {
$componentContent = [];
// Find the related component in the article object.
foreach ($this->articleData->data->content as $contentStationComponent) {
if (
($contentStationComponent->id === $contentStationIdentifier || $contentStationComponent->identifier === $contentStationIdentifier) &&
property_exists($contentStationComponent, 'content') && property_exists($contentStationComponent->content, $contentProperty)
) {
foreach ($contentStationComponent->content->{$contentProperty} as $text) {
$text_content = Html::escape($text->{$textProperty});
if (property_exists($text, 'attributes')) {
$componentContent[] = $this->applyTemplate($text_content, 'attribute', $text->attributes);
} else {
$componentContent[] = $text->{$textProperty};
}
}
}
}
// If there is only one value in the array, then only the value should be returned.
if (count($componentContent) === 1) {
$componentContent = $componentContent[0];
}
if (empty($componentContent)) {
return FALSE;
} else {
return $componentContent;
}
}
/**
* Apply template to the component
*
* @param string $text
* Text from the component, to which the template(s) should by applied.
* @param string $type
* Type of the template: component, attribute.
* @param array $attributes
* Attributes with data about the templates.
*
* @return string
*/
private function applyTemplate($text, $type, $attributes = NULL) {
$template = \Drupal::service('ww_publish.template');
foreach ($attributes as $attribute => $attributeValue) {
// Attribute templates are expected to exist or structure is lost,
// call apply() directly to trigger a warning log message about
// missing templates.
if ($attribute === 'comment') {
continue;
}
$text = $template->apply($attribute, $type, [
'insert' => $text,
$attribute => $attributeValue,
]) ?? $text;
}
return $text;
}
/**
* Get the WoodWing component.
*
* @param string $contentStationIdentifier
* WoodWing Studio identifier.
* @param string $contentProperty
* Property in the content object.
*
* @return Object
*/
private function getComponent($contentStationIdentifier, $contentProperty = NULL) {
// Find the related component in the article object.
foreach ($this->articleData->data->content as $contentStationComponent) {
if ($contentStationComponent->id === $contentStationIdentifier || $contentStationComponent->identifier === $contentStationIdentifier) {
if ($contentProperty) {
return $contentStationComponent->content->{$contentProperty};
}
else {
return $contentStationComponent;
}
}
}
return NULL;
}
/**
* Returns a reference ID for the given identifier.
*
* Currently only metadata identfiers like metadata:ExtraMetaData|Something
* are supported.
*
* @param string[] $woodwing_identifier
* The woodwing identifier, already split on the |.
*
* @return int|string|null
* The target entity ID if one could be identified.
*/
public function getReferenceFromHandler($woodwing_identifier) {
// @todo Support content components as well for a lookup? Abstract the
// different lookup methods behind a single API on Message?
if (\strpos($woodwing_identifier[0], 'metadata:') === 0 && count($woodwing_identifier) >= 2) {
$woodwing_identifier[0] = \str_replace('metadata:', '', $woodwing_identifier[0]);
if ($value = $this->message->getArticleMetadata()->getMetadataByIdentifier(...$woodwing_identifier)) {
// Attempt to fetch a reference for the given field as an exact
// match, assume that there is only one.
/** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager $autocomplete */
$selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
$options = $this->fieldConfig->getSetting('handler_settings') + [
'target_type' => $this->fieldConfig->getSetting('target_type'),
'handler' => $this->fieldConfig->getSetting('handler'),
];
try {
$handler = $selection_manager->getInstance($options);
$entities = $handler->getReferenceableEntities($value, '=', 1);
if ($entities) {
$entities = reset($entities);
return key($entities);
}
}
catch (\Exception $e) {
$this->logger->error('Unexpected error when trying to find reference: @message', ['@message' => $e->getMessage()]);
}
}
}
}
}
