gathercontent.module in GatherContent 8.3
Same filename and directory in other branches
Main module file for GatherContent module.
File
gathercontent.moduleView source
<?php
/**
* @file
* Main module file for GatherContent module.
*/
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\gathercontent\DAO\Content;
use Drupal\gathercontent\DAO\Project;
use Drupal\gathercontent\DAO\Template;
use Drupal\gathercontent\Entity\Mapping;
use Drupal\gathercontent\Entity\OperationItem;
use Drupal\gathercontent\Event\GatherContentEvents;
use Drupal\gathercontent\Event\PostImportEvent;
use Drupal\gathercontent\Event\PostNodeSaveEvent;
use Drupal\gathercontent\Event\PostNodeUploadEvent;
use Drupal\gathercontent\Event\PostUploadEvent;
use Drupal\gathercontent\Event\PreNodeSaveEvent;
use Drupal\gathercontent\Event\PreNodeUploadEvent;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\taxonomy\Entity\Term;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Implements hook_entity_base_field_info().
*
* Add a 'GC mapping ID' and 'GC ID fields' base field to all node types.
*
* {@inheritdoc}
*/
function gathercontent_entity_base_field_info(EntityTypeInterface $entity_type) {
$fields = [];
if ($entity_type
->id() === 'node') {
$fields['gc_mapping_id'] = $storage_definition = BaseFieldDefinition::create('integer')
->setLabel(t('GC mapping ID'))
->setDescription(t('The ID of GatherContent mapping.'))
->setReadOnly(TRUE);
$fields['gc_id'] = $storage_definition = BaseFieldDefinition::create('integer')
->setLabel(t('GC ID'))
->setDescription(t('The ID of GatherContent content.'))
->setReadOnly(TRUE);
}
if ($entity_type
->id() === 'file') {
$fields['gc_id'] = $storage_definition = BaseFieldDefinition::create('integer')
->setLabel(t('GC ID'))
->setDescription(t('The ID of GatherContent content.'))
->setReadOnly(TRUE);
}
return $fields;
}
/**
* Function for fetching, creating and updating content from GatherContent.
*
* @param int $gc_id
* ID of GatherContent piece of content.
* @param string $uuid
* UUID of \Drupal\gathercontent\Entity\Operation.
* @param bool $drupal_status
* Drupal status - published/unpublished.
* @param string $node_update_method
* Name of the node update method.
* @param int|null $status
* ID of status from GatherContent.
* @param string|null $parent_menu_item
* Parent menu item ID if we want to create menu item.
*
* @return bool
* Return nid if operation was successful.
*/
function _gc_fetcher($gc_id, $uuid, $drupal_status, $node_update_method, $status = NULL, $parent_menu_item = NULL) {
$user = \Drupal::currentUser();
$tsid = NULL;
$content_obj = new Content();
$content = $content_obj
->getContent($gc_id);
if (!empty($status)) {
$status_obj = new Project();
$status = $status_obj
->getStatus($content->project_id, $status);
}
$temp_obj = new Template();
$template = $temp_obj
->getTemplate($content->template_id);
$operation_item = \Drupal::entityTypeManager()
->getStorage('gathercontent_operation_item')
->create([
'operation_uuid' => $uuid,
'item_status' => !empty($status) ? $status->name : $content->status->data->name,
'item_status_color' => !empty($status) ? $status->color : $content->status->data->color,
'template_name' => $template->name,
'item_name' => $content->name,
'gc_id' => $gc_id,
]);
$mapping_id = Drupal::entityQuery('gathercontent_mapping')
->condition('gathercontent_project_id', $content->project_id)
->condition('gathercontent_template_id', $content->template_id)
->execute();
if (!empty($mapping_id)) {
$mapping = Mapping::load(reset($mapping_id));
// If mapping exists, start mapping remote fields to local ones.
$mapping_data = unserialize($mapping
->getData());
if (empty($mapping_data)) {
return FALSE;
}
$mapping_data_copy = $mapping_data;
$first = array_shift($mapping_data_copy);
$content_type = $mapping
->getContentType();
$langcode = isset($first['language']) ? $first['language'] : Language::LANGCODE_NOT_SPECIFIED;
$entity = gc_get_destination_node($gc_id, $node_update_method, $content_type, $langcode);
$entity
->set('gc_id', $gc_id);
$entity
->set('gc_mapping_id', $mapping
->id());
$entity
->setOwnerId($user
->id());
if ($entity
->isNew()) {
$entity
->setPublished($drupal_status);
}
if ($entity !== FALSE) {
/** @var \Drupal\node\NodeInterface $entity */
try {
$content_obj = new Content();
$files = $content_obj
->getFiles($gc_id);
$is_translatable = \Drupal::moduleHandler()
->moduleExists('content_translation') && \Drupal::service('content_translation.manager')
->isEnabled('node', $mapping
->getContentType());
foreach ($content->config as $pane) {
$is_translatable &= isset($mapping_data[$pane->name]['language']) && $mapping_data[$pane->name]['language'] != Language::LANGCODE_NOT_SPECIFIED;
if ($is_translatable) {
$language = $mapping_data[$pane->name]['language'];
if (!$entity
->hasTranslation($language)) {
$entity
->addTranslation($language);
if ($entity
->isNew()) {
$entity
->getTranslation($language)
->setPublished($drupal_status);
}
}
}
else {
$language = Language::LANGCODE_NOT_SPECIFIED;
}
foreach ($pane->elements as $field) {
if (isset($mapping_data[$pane->name]['elements'][$field->name]) && !empty($mapping_data[$pane->name]['elements'][$field->name])) {
$local_field_name = $mapping_data[$pane->name]['elements'][$field->name];
if (isset($mapping_data[$pane->name]['type']) && $mapping_data[$pane->name]['type'] === 'content' || !isset($mapping_data[$pane->name]['type'])) {
gc_gc_process_content_pane($entity, $local_field_name, $field, $is_translatable, $language, $files);
}
elseif (isset($mapping_data[$pane->name]['type']) && $mapping_data[$pane->name]['type'] === 'metatag') {
gc_gc_process_metatag_pane($entity, $local_field_name, $field, $mapping
->getContentType(), $is_translatable, $language);
}
}
}
}
if (!$is_translatable && empty($entity
->getTitle())) {
$entity
->setTitle($content->name);
}
\Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::PRE_NODE_SAVE, new PreNodeSaveEvent($entity, $content, $files));
$entity
->save();
// Create menu link items.
$menu_link_defaults = menu_ui_get_menu_link_defaults($entity);
if (!(bool) $menu_link_defaults['id']) {
if ($is_translatable) {
$languages = $entity
->getTranslationLanguages();
$original_link_id = NULL;
foreach ($languages as $langcode => $language) {
$localized_entity = $entity
->hasTranslation($langcode) ? $entity
->getTranslation($langcode) : NULL;
if (!is_null($localized_entity)) {
gc_create_menu_link($entity
->id(), $localized_entity
->getTitle(), $parent_menu_item, $langcode, $original_link_id);
}
}
}
else {
gc_create_menu_link($entity
->id(), $entity
->getTitle(), $parent_menu_item);
}
}
\Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::POST_NODE_SAVE, new PostNodeSaveEvent($entity, $content, $files));
$operation_item->status = "Success";
$operation_item->nid = $entity
->id();
$operation_item
->save();
return $entity
->id();
} catch (Exception $e) {
\Drupal::logger('gc_import')
->error(print_r($e, TRUE), []);
$operation_item->status = "Operation failed:" . $e
->getMessage();
$operation_item
->save();
return FALSE;
}
}
else {
$operation_item->status = "System error, please contact you administrator.";
$operation_item
->save();
return FALSE;
}
}
else {
$operation_item->status = "Operation failed: Template not mapped.";
$operation_item
->save();
return FALSE;
}
}
/**
* Get Node object based on type of update.
*
* @param int $gc_id
* ID of item in GatherContent.
* @param string $node_update_method
* Name of the node update method.
* @param int $node_type_id
* ID of the node type.
* @param string $langcode
* Language of translation if applicable.
*
* @return \Drupal\node\NodeInterface
* Return loaded node.
*/
function gc_get_destination_node($gc_id, $node_update_method, $node_type_id, $langcode) {
switch ($node_update_method) {
case 'update_if_not_changed':
$result = \Drupal::entityQuery('node')
->condition('gc_id', $gc_id)
->sort('created', 'DESC')
->range(0, 1)
->execute();
if ($result) {
$node = Node::load(reset($result));
$query_result = \Drupal::entityQuery('gathercontent_operation_item')
->condition('gc_id', $gc_id)
->sort('changed', 'DESC')
->range(0, 1)
->execute();
$operation = OperationItem::load(reset($query_result));
if ($node
->getChangedTime() === $operation
->getChangedTime()) {
return $node;
}
}
break;
case 'always_update':
$result = \Drupal::entityQuery('node')
->condition('gc_id', $gc_id)
->sort('created', 'DESC')
->range(0, 1)
->execute();
if ($result) {
return Node::load(reset($result));
}
break;
}
return Node::create([
'type' => $node_type_id,
'langcode' => $langcode,
]);
}
/**
* Processing function for metatag panes.
*
* @param \Drupal\node\NodeInterface $entity
* Object of node.
* @param string $local_field_name
* Name of local Drupal field.
* @param object $field
* Object of GatherContent field.
* @param string $content_type
* Name of Content type, we are mapping to.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
*
* @throws \Exception
* If content save fails, exceptions is thrown.
*/
function gc_gc_process_metatag_pane(NodeInterface &$entity, $local_field_name, $field, $content_type, $is_translatable, $language) {
if (\Drupal::moduleHandler()
->moduleExists('metatag') && check_metatag($content_type)) {
$metatag_fields = get_metatag_fields($content_type);
foreach ($metatag_fields as $metatag_field) {
if ($is_translatable) {
$current_value = unserialize($entity
->getTranslation($language)->{$metatag_field}->value);
$current_value[$local_field_name] = $field->value;
$entity
->getTranslation($language)->{$metatag_field}->value = serialize($current_value);
}
else {
$current_value = unserialize($entity->{$metatag_field}->value);
$current_value[$local_field_name] = $field->value;
$entity->{$metatag_field}->value = serialize($current_value);
}
}
}
else {
throw new Exception("Metatag module not enabled or entity doesn't support\n metatags while trying to map values with metatag content.");
}
}
/**
* Processing function for content panes.
*
* @param \Drupal\node\NodeInterface $entity
* Object of node.
* @param string $local_field_name
* Name of local Drupal field.
* @param object $field
* Object of GatherContent field.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
* @param array $files
* Array of files fetched from GatherContent.
*/
function gc_gc_process_content_pane(NodeInterface &$entity, $local_field_name, $field, $is_translatable, $language, array $files) {
$field_info = FieldConfig::loadByName('node', $entity
->bundle(), $local_field_name);
if (!is_null($field_info)) {
$is_translatable = $is_translatable && $field_info
->isTranslatable();
}
switch ($field->type) {
case 'files':
gc_gc_process_files_field($entity, $local_field_name, $field->name, $is_translatable, $language, $files);
break;
case 'choice_radio':
gc_gc_process_choice_radio_field($entity, $local_field_name, $is_translatable, $language, $field->options);
break;
case 'choice_checkbox':
gc_gc_process_choice_checkbox_field($entity, $local_field_name, $is_translatable, $language, $field->options);
break;
case 'section':
gc_gc_process_section_field($entity, $local_field_name, $is_translatable, $language, $field);
break;
default:
gc_gc_process_default_field($entity, $local_field_name, $is_translatable, $language, $field);
break;
}
}
/**
* Create menu link if requested.
*
* @param int $nid
* ID of \Drupal\node\NodeInterface object.
* @param string $title
* Title for menu link.
* @param string $plid
* Parent menu link ID, null if we don't want to create menu link.
* @param null|string $lang
* Langcode for menu link.
* @param null|int $original_link_id
* ID of menu link item in default language.
*/
function gc_create_menu_link($nid, $title, $plid, $lang = NULL, &$original_link_id = NULL) {
$weight = 1;
if (!empty($plid)) {
if (is_null($lang)) {
// Single language node.
list($menu_name, $mlid) = explode(':', $plid);
// Get parent menu link ID.
if ($menu_name === 'node') {
_gc_get_menu_by_gc_id($mlid, $menu_name);
}
$link = [
'link' => [
'uri' => 'entity:node/' . $nid,
],
'title' => $title,
'menu_name' => $menu_name,
'parent' => $mlid,
];
MenuLinkContent::create($link)
->set('weight', $weight)
->save();
}
elseif (\Drupal::moduleHandler()
->moduleExists('content_translation') && \Drupal::service('content_translation.manager')
->isEnabled('menu_link_content')) {
if (!is_null($lang) && is_null($original_link_id)) {
// Multi language node - first language.
list($menu_name, $mlid) = explode(':', $plid);
// Get parent menu link ID.
if ($menu_name === 'node') {
_gc_get_menu_by_gc_id($mlid, $menu_name, $lang);
}
$link = [
'link' => [
'uri' => 'entity:node/' . $nid,
],
'title' => $title,
'menu_name' => $menu_name,
'parent' => $mlid,
'langcode' => $lang,
];
$menu_link = MenuLinkContent::create($link);
$menu_link
->set('weight', $weight);
$menu_link
->save();
$original_link_id = $menu_link
->id();
}
elseif (!is_null($lang) && !is_null($original_link_id)) {
// Multi language node - other language.
list($menu_name, $mlid) = explode(':', $plid);
if ($menu_name === 'node') {
_gc_get_menu_by_gc_id($mlid, $menu_name, $lang);
}
$link = [
'link' => [
'uri' => 'entity:node/' . $nid,
],
'title' => $title,
'menu_name' => $menu_name,
'parent' => $mlid,
'langcode' => $lang,
];
// Load parent item.
$original_item = MenuLinkContent::load($original_link_id);
$original_item
->addTranslation($lang, $link);
$original_item
->save();
}
}
}
}
/**
* Load menu name and menu link id for other languages by node ID.
*
* @param int $mlid
* Menu link ID.
* @param string $menu_name
* Name of the menu.
* @param string|null $language
* Langcode if menu link item will be translatable.
*/
function _gc_get_menu_by_gc_id(&$mlid, &$menu_name, $language = NULL) {
// Load node by gc_id.
$node_ids = \Drupal::entityQuery('node')
->condition('gc_id', $mlid)
->execute();
if (!empty($node_ids)) {
// Load menu_link by node_id.
$node = reset($node_ids);
$ml_result = \Drupal::entityQuery('menu_link_content')
->condition('link.uri', 'entity:node/' . $node);
if (!is_null($language)) {
$ml_result
->condition('langcode', $language);
}
$mls = $ml_result
->execute();
if (!empty($mls)) {
$ml = reset($mls);
$ml_object = MenuLinkContent::load($ml);
$menu_name = $ml_object
->getMenuName();
$mlid = 'menu_link_content:' . $ml_object
->uuid();
}
}
}
/**
* Default processing function, when no other matches found, usually for text.
*
* @param \Drupal\node\NodeInterface $entity
* Object of node.
* @param string $local_field_name
* Local field name.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
* @param object $field
* Object with field attributes.
*/
function gc_gc_process_default_field(NodeInterface &$entity, $local_field_name, $is_translatable, $language, $field) {
$value = $field->value;
$target =& $entity;
if ($is_translatable) {
$target = $entity
->getTranslation($language);
}
// Title is not a field, breaks everything. Short-circuit here.
if ($local_field_name === 'title') {
$target
->setTitle($value);
return;
}
// For all non-title fields, decide what to do based on Drupal field type.
$field_info = FieldConfig::loadByName('node', $entity
->bundle(), $local_field_name);
switch ($field_info
->getType()) {
case 'datetime':
$value = strtotime($value);
if ($value === FALSE) {
// If we failed to convert to a timestamp, abort.
return;
}
$target->{$local_field_name} = [
'value' => gmdate(DATETIME_DATETIME_STORAGE_FORMAT, $value),
];
break;
case 'date':
$value = strtotime($value);
if ($value === FALSE) {
return;
}
$target->{$local_field_name} = [
'value' => gmdate(DATETIME_DATE_STORAGE_FORMAT, $value),
];
break;
default:
// Probably some kind of text field.
$target->{$local_field_name} = [
'value' => $value,
'format' => $field->plain_text ? 'plain_text' : 'basic_html',
];
break;
}
}
/**
* Processing function for section type of field.
*
* @param \Drupal\node\NodeInterface $node
* Object of node.
* @param string $local_field_name
* Local field name.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
* @param object $field
* Object with field attributes.
*/
function gc_gc_process_section_field(NodeInterface &$node, $local_field_name, $is_translatable, $language, $field) {
if ($is_translatable) {
$node
->getTranslation($language)->{$local_field_name} = [
'value' => '<h3>' . $field->title . '</h3>' . $field->subtitle,
'format' => 'basic_html',
];
}
else {
$node->{$local_field_name} = [
'value' => '<h3>' . $field->title . '</h3>' . $field->subtitle,
'format' => 'basic_html',
];
}
}
/**
* Processing function for checkbox type of field.
*
* @param \Drupal\node\NodeInterface $node
* Object of node.
* @param string $local_field_name
* Local field name.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
* @param array $options
* Array of options.
*/
function gc_gc_process_choice_checkbox_field(NodeInterface &$node, $local_field_name, $is_translatable, $language, array $options) {
$field = FieldConfig::loadByName('node', $node
->bundle(), $local_field_name);
$node->{$local_field_name} = [
NULL,
];
$selected_options = [];
foreach ($options as $option) {
if ($option->selected) {
if ($field
->getType() === 'entity_reference') {
/** @var \Drupal\taxonomy\Entity\Term $term */
$term = array_shift(\Drupal::entityTypeManager()
->getStorage('taxonomy_term')
->loadByProperties([
'gathercontent_option_ids' => $option->name,
]));
$selected_options[] = $term
->id();
}
else {
$selected_options[] = $option->name;
}
}
if ($is_translatable) {
$node
->getTranslation($language)->{$local_field_name} = $selected_options;
}
else {
$node->{$local_field_name} = $selected_options;
}
}
}
/**
* Processing function for radio type of field.
*
* @param \Drupal\node\NodeInterface $node
* Object of node.
* @param string $local_field_name
* Local field name.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
* @param array $options
* Array of options.
*/
function gc_gc_process_choice_radio_field(NodeInterface &$node, $local_field_name, $is_translatable, $language, array $options) {
$field = FieldConfig::loadByName('node', $node
->bundle(), $local_field_name);
foreach ($options as $option) {
if (!$option->selected) {
continue;
}
if (isset($option->value)) {
if (empty($option->value)) {
continue;
}
// Dealing with "Other" option.
if ($field
->getType() === 'entity_reference') {
// Load vocabulary id.
if (!empty($field
->getSetting('handler_settings')['auto_create_bundle'])) {
$vid = $field
->getSetting('handler_settings')['auto_create_bundle'];
}
else {
$handler_settings = $field
->getSetting('handler_settings');
$handler_settings = reset($handler_settings);
$vid = array_shift($handler_settings);
}
// Prepare confitions.
$condition_array = [
'name' => $option->value,
'vid' => $vid,
];
if ($is_translatable && $language !== LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$condition_array['langcode'] = $language;
}
$terms = \Drupal::entityTypeManager()
->getStorage('taxonomy_term')
->loadByProperties($condition_array);
/** @var \Drupal\taxonomy\Entity\Term $term */
$term = array_shift($terms);
if (empty($term)) {
$term = Term::create([
'vid' => $vid,
'name' => $option->value,
'langcode' => $language,
]);
$term
->save();
}
if ($is_translatable && $node
->hasTranslation($language)) {
$node
->getTranslation($language)
->set($local_field_name, $term
->id());
}
else {
$node
->set($local_field_name, $term
->id());
}
}
else {
if ($is_translatable) {
$node
->getTranslation($language)->{$local_field_name}->value = $option->value;
}
else {
$node->{$local_field_name}->value = $option->value;
}
}
}
else {
// Dealing with predefined options.
if ($field
->getType() === 'entity_reference') {
$terms = \Drupal::entityTypeManager()
->getStorage('taxonomy_term')
->loadByProperties([
'gathercontent_option_ids' => $option->name,
]);
/** @var \Drupal\taxonomy\Entity\Term $term */
$term = array_shift($terms);
if (!empty($term)) {
if ($is_translatable) {
$node
->getTranslation($language)
->set($local_field_name, $term
->id());
}
else {
$node
->set($local_field_name, $term
->id());
}
}
}
else {
if ($is_translatable) {
$node
->getTranslation($language)->{$local_field_name}->value = $option->name;
}
else {
$node->{$local_field_name}->value = $option->name;
}
}
}
}
}
/**
* Processing function for file type of field.
*
* @param \Drupal\node\NodeInterface $node
* Object of node.
* @param string $local_field_name
* Local field name.
* @param string $gc_field_name
* Name of field in GatherContent.
* @param bool $is_translatable
* Indicator if node is translatable.
* @param string $language
* Language of translation if applicable.
* @param array $files
* Array of remote files.
*/
function gc_gc_process_files_field(NodeInterface &$node, $local_field_name, $gc_field_name, $is_translatable, $language, array $files) {
$found_files = [];
/** @var \Drupal\field\Entity\FieldConfig $translatable_file_config */
$translatable_file_config = $node
->getFieldDefinition($local_field_name);
$translatable_file = $translatable_file_config
->get('third_party_settings')['content_translation']['translation_sync']['file'];
foreach ($files as $file) {
if ($file->field === $gc_field_name) {
$drupal_files = \Drupal::entityQuery('file')
->condition('gc_id', $file->id)
->condition('filename', $file->filename)
->execute();
if (empty($drupal_files)) {
if (!($node
->language()
->getId() !== $language && $translatable_file === '0')) {
$file_dir = $node
->getFieldDefinition($local_field_name)
->getSetting('file_directory');
$file_dir = PlainTextOutput::renderFromHtml(\Drupal::token()
->replace($file_dir, []));
$uri_scheme = $node
->getFieldDefinition($local_field_name)
->getFieldStorageDefinition()
->getSetting('uri_scheme') . '://';
$create_dir = \Drupal::service('file_system')
->realpath($uri_scheme) . '/' . $file_dir;
file_prepare_directory($create_dir, FILE_CREATE_DIRECTORY);
$local_file = file_save_data(file_get_contents($file->url), $uri_scheme . $file_dir . '/' . $file->filename);
$local_file
->set('gc_id', $file->id)
->set('langcode', $language)
->set('filesize', $file->size);
$found_files[] = [
'target_id' => $local_file
->id(),
];
}
}
else {
$drupal_file = reset($drupal_files);
$found_files[] = [
'target_id' => $drupal_file,
];
}
}
}
if ($is_translatable) {
$node
->getTranslation($language)
->set($local_field_name, $found_files);
}
else {
$node
->set($local_field_name, $found_files);
}
}
/**
* Batch operation callback.
*
* We are doing real import thing here.
*
* @param int $gc_id
* ID of content we want to import.
* @param int $status_id
* ID of status, if 0 then we don't want to change status.
* @param string $operation_uuid
* UUID of operation.
* @param bool $drupal_status
* Status on node in Drupal - published/unpublished.
* @param string $node_update_method
* Name of the node update method.
* @param int|null $parent_menu_item
* ID of mlid.
* @param array $context
* Context of operation.
*/
function gathercontent_import_process($gc_id, $status_id, $operation_uuid, $drupal_status, $node_update_method, $parent_menu_item = NULL, array &$context = []) {
if (($nid = _gc_fetcher($gc_id, $operation_uuid, $drupal_status, $node_update_method, $status_id, $parent_menu_item)) !== FALSE) {
if ($status_id != 0) {
// Change status.
$content_obj = new Content();
$content_obj
->updateStatus($gc_id, $status_id);
}
}
$context['results']['uuid'] = $operation_uuid;
}
/**
* Finished callback.
*
* {@inheritdoc}
*/
function gathercontent_import_finished($success, $results, $operations) {
if ($success) {
// Select all items with uuid.
$result = \Drupal::entityQuery('gathercontent_operation_item')
->condition('operation_uuid', $results['uuid'])
->execute();
if (!empty($result)) {
$operation_items = OperationItem::loadMultiple($result);
$success_counter = 0;
$nids = [
'success' => [],
'failed' => [],
];
foreach ($operation_items as $operation_item) {
/** @var \Drupal\gathercontent\Entity\OperationItem $operation_item */
if ($operation_item
->getStatus() === 'Success') {
$success_counter++;
$nids['success'][] = [
'nid' => $operation_item
->get('nid')->value,
'gc_id' => $operation_item
->get('gc_id')->value,
];
}
else {
$nids['failed'][] = [
'nid' => $operation_item
->get('nid')->value,
'gc_id' => $operation_item
->get('gc_id')->value,
];
}
}
$unsuccessful = count($result) - $success_counter;
drupal_set_message(\Drupal::translation()
->formatPlural($success_counter, '1 item was imported successfully.', '@count items were imported successfully.'));
if ($unsuccessful > 0) {
drupal_set_message(\Drupal::translation()
->formatPlural($unsuccessful, '1 item was not imported. Check errors below.', '@count items were not imported. Check errors below.'), 'error');
}
\Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::POST_IMPORT, new PostImportEvent($nids['success'], $nids['failed'], $results['uuid']));
}
return new RedirectResponse('admin/config/gathercontent/import/result/' . $results['uuid']);
}
else {
$error_operation = reset($operations);
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', [
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
]), 'error');
}
return TRUE;
}
/**
* Batch operation callback.
*
* We are doing real update thing here.
*
* @param int $gc_id
* ID of content we want to import.
* @param string $operation_uuid
* UUID of operation.
* @param string $node_update_method
* Name of the node update method.
* @param array $context
* Context of operation.
*/
function gathercontent_update_process($gc_id, $operation_uuid, $node_update_method, array &$context) {
_gc_fetcher($gc_id, $operation_uuid, 0, $node_update_method);
$context['results']['uuid'] = $operation_uuid;
}
/**
* Finished callback.
*
* @inheritdoc
*/
function gathercontent_update_finished($success, $results, $operations) {
if ($success) {
// Select all items with uuid.
$result = \Drupal::entityQuery('gathercontent_operation_item')
->condition('operation_uuid', $results['uuid'])
->execute();
if (!empty($result)) {
$operation_items = OperationItem::loadMultiple($result);
$success_counter = 0;
$nids = [
'success' => [],
'failed' => [],
];
foreach ($operation_items as $operation_item) {
/** @var \Drupal\gathercontent\Entity\OperationItem $operation_item */
if ($operation_item
->getStatus() === 'Success') {
$success_counter++;
$nids['success'][] = [
'nid' => $operation_item
->get('nid')->value,
'gc_id' => $operation_item
->get('gc_id')->value,
];
}
else {
$nids['failed'][] = [
'nid' => $operation_item
->get('nid')->value,
'gc_id' => $operation_item
->get('gc_id')->value,
];
}
}
$unsuccessful = count($result) - $success_counter;
drupal_set_message(\Drupal::translation()
->formatPlural($success_counter, '1 item was imported successfully.', '@count items were imported successfully.'));
if ($unsuccessful > 0) {
drupal_set_message(\Drupal::translation()
->formatPlural($unsuccessful, '1 item was not imported. Check errors below.', '@count items were not imported. Check errors below.'), 'error');
}
\Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::POST_IMPORT, new PostImportEvent($nids['success'], $nids['failed'], $results['uuid']));
}
return new RedirectResponse('admin/config/gathercontent/update/result/' . $results['uuid']);
}
else {
$error_operation = reset($operations);
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', [
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
]), 'error');
}
return TRUE;
}
/**
* Upload batch operation callback.
*
* @param \Drupal\node\NodeInterface $entity
* Object of entity we want to upload.
* @param string $uuid
* UUID of \Drupal\gathercontent\Entity\Operation entity.
* @param array $context
* Context of operation.
*/
function gathercontent_upload_process(NodeInterface $entity, $uuid, array &$context) {
// 1. Load template from remote
// 2. Compare local and remote template
// 3. If templates are same, load node from remote.
// 4. Set values based on mapping.
$mapping = Mapping::load($entity
->get('gc_mapping_id')
->getValue());
$tmp_obj = new Template();
$remote_template = $tmp_obj
->getTemplate($mapping
->getGathercontentTemplateId());
$cont_obj = new Content();
$remote_node = $cont_obj
->getContent($entity
->get('gc_id')
->getValue());
$config = $remote_node->config;
$mapping_data = unserialize($mapping
->getData());
$operation_item = \Drupal::entityTypeManager()
->getStorage('gathercontent_operation_item')
->create([
'operation_uuid' => $uuid,
'item_status' => $remote_node->status->data->name,
'item_status_color' => $remote_node->status->data->color,
'template_name' => $remote_template->name,
'item_name' => $remote_node->name,
'gc_id' => $entity
->get('gc_id'),
'nid' => $entity
->id(),
]);
if ($remote_template->config == unserialize($mapping
->getTemplate())->config) {
try {
foreach ($config as &$pane) {
$is_translatable = \Drupal::moduleHandler()
->moduleExists('content_translation') && \Drupal::service('content_translation.manager')
->isEnabled('node', $mapping
->getContentType()) && isset($mapping_data[$pane->name]['language']) && $mapping_data[$pane->name]['language'] != Language::LANGCODE_NOT_SPECIFIED;
if ($is_translatable) {
$language = $mapping_data[$pane->name]['language'];
}
else {
$language = Language::LANGCODE_NOT_SPECIFIED;
}
foreach ($pane->elements as &$field) {
if (isset($mapping_data[$pane->name]['elements'][$field->name]) && !empty($mapping_data[$pane->name]['elements'][$field->name])) {
$local_field_name = $mapping_data[$pane->name]['elements'][$field->name];
if (isset($mapping_data[$pane->name]['type']) && $mapping_data[$pane->name]['type'] === 'content' || !isset($mapping_data[$pane->name]['type'])) {
$field_info = FieldConfig::loadByName('node', $entity
->bundle(), $local_field_name);
if (!is_null($field_info)) {
$is_translatable = $is_translatable && $field_info
->isTranslatable();
}
switch ($field->type) {
case 'files':
// There is currently no API for manipulating with files.
break;
case 'choice_radio':
$option_names = [];
foreach ($field->options as &$option) {
// Set selected to false for each option.
$option->selected = FALSE;
$option_names[] = $option->name;
}
// Fetch local selected option.
if ($is_translatable) {
$selected = $entity
->getTranslation($language)->{$local_field_name}->value;
}
else {
$selected = $entity->{$local_field_name}->value;
}
if (!in_array($selected, $option_names)) {
// If it's other, then find that option in remote.
foreach ($field->options as &$option) {
if (isset($option->value)) {
$option->selected = TRUE;
$option->value = $selected;
}
}
}
else {
// If it's checkbox, find it by remote option name,
// which should be same.
foreach ($field->options as &$option) {
if ($option->name == $selected) {
$option->selected = TRUE;
}
}
}
break;
case 'choice_checkbox':
foreach ($field->options as &$option) {
// Set selected to false for each option.
$option->selected = FALSE;
}
// Fetch local selected option.
if ($is_translatable) {
$selected = $entity
->getTranslation($language)->{$local_field_name}->value;
}
else {
$selected = $entity->{$local_field_name}->value;
}
// If it's checkbox, find it by remote option name,
// which should be same.
foreach ($field->options as &$option) {
if (isset($selected[$option->name])) {
$option->selected = TRUE;
}
}
break;
case 'section':
// We don't upload this because this field shouldn't be
// edited.
break;
default:
if ($local_field_name === 'title') {
if ($is_translatable) {
$field->value = $entity
->getTranslation($language)
->getTitle();
}
else {
$field->value = $entity
->getTitle();
}
}
else {
if ($is_translatable) {
$field->value = $entity
->getTranslation($language)->{$local_field_name}->value;
}
else {
$field->value = $entity->{$local_field_name}->value;
}
}
break;
}
}
elseif ($mapping_data[$pane->name]['type'] === 'metatag') {
if (\Drupal::moduleHandler()
->moduleExists('metatag') && check_metatag($entity
->getType())) {
$metatag_fields = get_metatag_fields($entity
->getType());
foreach ($metatag_fields as $metatag_field) {
if ($is_translatable) {
$field->value = $entity
->getTranslation($language)->{$metatag_field}
->value();
}
else {
$field->value = $entity->{$metatag_field}
->value();
}
}
}
}
}
else {
$operation_item->status = "System error, please contact you administrator.";
$operation_item
->save();
}
}
}
$event = \Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::PRE_NODE_UPLOAD, new PreNodeUploadEvent($entity, $config));
/** @var \Drupal\gathercontent\Event\PreNodeUploadEvent $event */
$config = $event
->getGathercontentValues();
if ($cont_obj
->postContent($entity
->get('gc_id')
->getValue(), $config)) {
$operation_item->status = "Success";
$operation_item
->save();
\Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::POST_NODE_UPLOAD, new PostNodeUploadEvent($entity, $config));
}
else {
$operation_item->status = 'Mapping doesn\'t match';
$operation_item
->save();
}
} catch (\Exception $e) {
\Drupal::logger('gc_upload')
->error(print_r($e, TRUE), []);
$operation_item->status = 'Mapping doesn\'t match';
$operation_item
->save();
}
}
else {
$operation_item->status = 'Mapping doesn\'t match';
$operation_item
->save();
}
$context['results']['uuid'] = $uuid;
}
/**
* Finished callback.
*
* @inheritdoc
*/
function gathercontent_upload_finished($success, $results, $operations) {
if ($success) {
// Select all items with uuid.
$result = \Drupal::entityQuery('gathercontent_operation_item')
->condition('operation_uuid', $results['uuid'])
->execute();
if (!empty($result)) {
$operation_items = OperationItem::loadMultiple($result);
$success_counter = 0;
$nids = [
'success' => [],
'failed' => [],
];
foreach ($operation_items as $operation_item) {
/** @var \Drupal\gathercontent\Entity\OperationItem $operation_item */
if ($operation_item
->getStatus() === 'Success') {
$success_counter++;
$nids['success'][] = [
'nid' => $operation_item
->get('nid')->value,
'gc_id' => $operation_item
->get('gc_id')->value,
];
}
else {
$nids['failed'][] = [
'nid' => $operation_item
->get('nid')->value,
'gc_id' => $operation_item
->get('gc_id')->value,
];
}
}
$unsuccessful = count($result) - $success_counter;
drupal_set_message(\Drupal::translation()
->formatPlural($success_counter, '1 item was uploaded successfully.', '@count items were uploaded successfully.'));
if ($unsuccessful > 0) {
drupal_set_message(\Drupal::translation()
->formatPlural($unsuccessful, '1 item was not uploaded. Check errors below.', '@count items were not uploaded. Check errors below.'), 'error');
}
\Drupal::service('event_dispatcher')
->dispatch(GatherContentEvents::POST_UPLOAD, new PostUploadEvent($nids['success'], $nids['failed'], $results['uuid']));
}
return new RedirectResponse('admin/config/gathercontent/upload/result/' . $results['uuid']);
}
else {
$error_operation = reset($operations);
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', [
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
]), 'error');
}
return TRUE;
}
/**
* Check if content type has any metatag fields.
*
* @param string $content_type
* Machine name of content type.
*
* @return bool
* TRUE if metatag field exists.
*/
function check_metatag($content_type) {
$instances = \Drupal::service('entity_field.manager')
->getFieldDefinitions('node', $content_type);
foreach ($instances as $name => $instance) {
/** @var \Drupal\Core\Field\FieldDefinitionInterface $instance */
if ($instance
->getType() === 'metatag') {
return TRUE;
}
}
return FALSE;
}
/**
* Get list of metatag fields.
*
* @param string $content_type
* Machine name of content type.
*
* @return array
* Array of metatag fields.
*/
function get_metatag_fields($content_type) {
$instances = \Drupal::service('entity_field.manager')
->getFieldDefinitions('node', $content_type);
$fields = [];
foreach ($instances as $name => $instance) {
/** @var \Drupal\Core\Field\FieldDefinitionInterface $instance */
if ($instance
->getType() === 'metatag') {
$fields[] = $instance
->getName();
}
}
return $fields;
}
Functions
Name | Description |
---|---|
check_metatag | Check if content type has any metatag fields. |
gathercontent_entity_base_field_info | Implements hook_entity_base_field_info(). |
gathercontent_import_finished | Finished callback. |
gathercontent_import_process | Batch operation callback. |
gathercontent_update_finished | Finished callback. |
gathercontent_update_process | Batch operation callback. |
gathercontent_upload_finished | Finished callback. |
gathercontent_upload_process | Upload batch operation callback. |
gc_create_menu_link | Create menu link if requested. |
gc_gc_process_choice_checkbox_field | Processing function for checkbox type of field. |
gc_gc_process_choice_radio_field | Processing function for radio type of field. |
gc_gc_process_content_pane | Processing function for content panes. |
gc_gc_process_default_field | Default processing function, when no other matches found, usually for text. |
gc_gc_process_files_field | Processing function for file type of field. |
gc_gc_process_metatag_pane | Processing function for metatag panes. |
gc_gc_process_section_field | Processing function for section type of field. |
gc_get_destination_node | Get Node object based on type of update. |
get_metatag_fields | Get list of metatag fields. |
_gc_fetcher | Function for fetching, creating and updating content from GatherContent. |
_gc_get_menu_by_gc_id | Load menu name and menu link id for other languages by node ID. |