cms_content_sync-3.0.x-dev/src/Controller/FlowControllerSimple.php
src/Controller/FlowControllerSimple.php
<?php
namespace Drupal\cms_content_sync\Controller;
use Drupal\cms_content_sync\Entity\Flow;
use Drupal\cms_content_sync\Entity\Pool;
use Drupal\cms_content_sync\Helper\SimpleFlowSetupHelper;
use Drupal\cms_content_sync\IFlowController;
use Drupal\cms_content_sync\Plugin\Type\EntityHandlerPluginManager;
use Drupal\cms_content_sync\PullIntent;
use Drupal\cms_content_sync\PushIntent;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\system\Entity\Menu;
/**
* The simple Flow controller.
*/
class FlowControllerSimple extends FlowControllerBase implements IFlowController {
public const ASSIGN_ALL_POOLS = 'force';
public const ASSIGN_POOLS_MANUALLY = 'allow';
public const MODE_AUTOMATICALLY = 'automatically';
public const MODE_MANUALLY = 'manually';
public const MODE_DEFAULT = 'default';
public const MODE_DEPENDENT = 'dependency';
public const MODE_IGNORE = 'disabled';
public const FLOW_FORM_VERSION = 1;
/**
* A virtual Flow is not saved to the database and only used temporarily.
*
* E.g. to serialize an entity at the SyncCoreEntityItemResource that is
* used by the embed service, e.g. to get taxonomy terms for the flow form
* to use the "subscribe only to" option.
*
* @var bool
*/
protected $virtual = FALSE;
/**
* Check if the flow is virutal.
*/
public function isVirtual($set = NULL) {
if (NULL !== $set) {
$this->virtual = $set;
}
return $this->virtual;
}
/**
* Create a flow configuration programmatically.
*
* @param string $type
* The type of the flow to be created (e.g. push or pull).
* @param string $flow_name
* The name of the flow.
* @param string $flow_id
* The id of the flow.
* @param bool $status
* Whether the flow is active or not.
* @param array $pools
* The pools that flow.
* @param array $dependencies
* An array of dependencies to be handled by the flow.
* @param bool $force_update
* Whether to force entity updates or not.
*
* @return \Drupal\cms_content_sync\Helper\SimpleFlowSetupHelper
* Returns the helper instance for the simple flow setup.
*/
public static function createFlow(string $type, string $flow_name, ?string $flow_id = NULL, $status = TRUE, ?array $pools = NULL, array $dependencies = [], bool $force_update = FALSE) {
$flows = Flow::getAll(TRUE);
// If no flow_id is given, create one.
if (empty($flow_id)) {
$flow_id = strtolower($flow_name);
$flow_id = preg_replace('@[^a-z0-9_]+@', '_', $flow_id);
}
if (!$force_update && array_key_exists($flow_id, $flows)) {
\Drupal::messenger()->addMessage('A flow with the machine name ' . $flow_id . ' already exists. Creation has been skipped.', 'warning');
return $flow_id;
}
$uuid_service = \Drupal::service('uuid');
$language_manager = \Drupal::service('language_manager');
$default_language = $language_manager->getDefaultLanguage();
$config = [
'dependencies' => $dependencies,
];
$flow_config = \Drupal::service('config.factory')->getEditable('cms_content_sync.flow.' . $flow_id);
// Setup base configurations.
$flow_config
->set('uuid', $uuid_service->generate())
->set('langcode', $default_language->getId())
->set('status', $status)
->set('id', $flow_id)
->set('name', $flow_name)
->set('type', $type)
->set('variant', Flow::VARIANT_SIMPLE)
->set('config', $config)
->set('simple_settings', [
'poolAssignment' => self::ASSIGN_ALL_POOLS,
'mode' => self::MODE_AUTOMATICALLY,
'deletions' => TRUE,
'embeddedDeletions' => TRUE,
'updateBehavior' => PullIntent::PULL_UPDATE_FORCE_AND_FORBID_EDITING,
'ignoreUnpublishedChanges' => TRUE,
'allowExplicitUnpublishing' => TRUE,
'pushMenuItems' => TRUE,
'pushPreviews' => TRUE,
'mergeLocalChanges' => FALSE,
'resolveUserReferences' => 'name',
'poolSelectionWidget' => 'checkboxes',
'entityTypeSettings' => [],
'pools' => $pools,
]);
$flow_config->save();
$flows = Flow::getAll(TRUE, TRUE);
return new SimpleFlowSetupHelper($flows[$flow_id]);
}
/**
* {@inheritDoc}
*/
public function getEntityTypeConfig($find_entity_type = NULL, $find_entity_bundle = NULL, $used_only = FALSE, $include_new_versions = FALSE, $invalidate = FALSE) {
$all = $this->buildEntityTypeConfig($include_new_versions, $invalidate);
if ($find_entity_type) {
if ($find_entity_bundle) {
if ('*' === $find_entity_bundle) {
return array_values($all[$find_entity_type])[0] ?? NULL;
}
return $all[$find_entity_type][$find_entity_bundle] ?? NULL;
}
return $all[$find_entity_type] ?? NULL;
}
return $all;
}
/**
* {@inheritDoc}
*/
public function needsEntityTypeUpdate() {
$old_versions = $this->getEntityTypeConfig(NULL, NULL, FALSE, FALSE);
$new_versions = $this->getEntityTypeConfig(NULL, NULL, FALSE, TRUE);
foreach ($old_versions as $entity_type_name => $bundles) {
foreach ($bundles as $bundle_name => $config) {
if ($config['version'] !== $new_versions[$entity_type_name][$bundle_name]['version']) {
return TRUE;
}
}
}
return FALSE;
}
/**
* {@inheritDoc}
*/
public function getPropertyConfig(string $entity_type, string $entity_bundle, string $property) {
$bundle_settings = $this->getEntityTypeConfig($entity_type, $entity_bundle);
if (empty($bundle_settings['properties'][$property])) {
return NULL;
}
return $bundle_settings['properties'][$property];
}
/**
* Get the values for the embed Flow form.
*
* @return array
* An array of the values for the embed Flow form.
*/
public function getFormValues() {
return [
'values' => $this->flow->simple_settings + [
'machineName' => $this->flow->id,
'name' => $this->flow->name,
'type' => $this->flow->type,
],
] + FlowControllerSimple::getFormConfig($this->flow);
}
/**
* Store the values from the embed Flow form.
*/
public function setFormValues(array $values) {
$this->flow->name = $values['name'];
unset($values['type'], $values['machineName'], $values['name']);
$this->flow->simple_settings = $values;
}
/**
* Get the values for the embed Flow.
*/
public static function getFormValuesForNewFlow(?Flow $flow) {
$values = $flow ? [
'machineName' => $flow->id,
'name' => $flow->name,
] : [
'simplifyEntityTypeSettings' => TRUE,
];
return [
'values' => $values,
] + FlowControllerSimple::getFormConfig($flow);
}
/**
* Update the entity type version.
*/
public function updateEntityTypeVersions() {
$status = \Drupal::state()->get('cms_content_sync.flow_status_' . $this->flow->id);
if (empty($status)) {
$status = [];
}
// Invalidate Flow cache.
Flow::clearFlowCache();
$types = $this->getEntityTypeConfig(NULL, NULL, FALSE, TRUE, TRUE);
$versions = [];
foreach ($types as $entity_type_name => $bundles) {
foreach ($bundles as $bundle_name => $config) {
$versions[$entity_type_name][$bundle_name] = $config['version'];
}
}
$status['entity_type_versions'] = $versions;
\Drupal::state()->set('cms_content_sync.flow_status_' . $this->flow->id, $status);
}
/**
* Check if the given pool is used by the flow.
*
* @param string $pool
* The pool to check.
*
* @return bool
* Returns true if the pool is used with the flow.
*/
public function usesPool($pool) {
$settings = $this->flow->simple_settings;
if (!isset($settings['pools']) || !is_array($settings['pools'])) {
return TRUE;
}
return in_array($pool->id, $settings['pools']);
}
/**
* Get the preview type.
*
* @param string $entity_type_name
* The entity type name to get the preview type for.
* @param string $bundle_name
* The bundle name to get the preview type for.
*
* @return string
* The preview type.
*/
public function getPreviewType($entity_type_name, $bundle_name) {
$config = $this->getEntityTypeConfig($entity_type_name, $bundle_name);
if (empty($config['preview'])) {
return Flow::PREVIEW_DISABLED;
}
return $config['preview'];
}
/**
* Get the allowed languages.
*/
public function getAllowedLanguages() {
$fallback_languages = [
'und',
'zxx',
];
return empty($this->flow->simple_settings['languages']) ? NULL : array_merge($this->flow->simple_settings['languages'], $fallback_languages);
}
/**
* Check if the flow push deletions of embeds.
*/
public function canPushEmbeddedDeletion() {
return !empty($this->flow->simple_settings['embeddedDeletions']);
}
/**
*
*/
protected function buildEntityTypeConfig($include_new_versions = FALSE, $invalidate = FALSE) {
static $cache = [];
if ($invalidate) {
$cache = [];
}
$version_index = $include_new_versions ? 'new' : 'existing';
$drupal_cache = \Drupal::cache();
$cache_item_data = NULL;
// Cache doesn't exist at all => ask Drupal cache.
if (empty($cache[$this->flow->id()]) && !$invalidate) {
$cache_item = $drupal_cache->get(Flow::CACHE_ITEM_NAME_FLOWS . '/' . $this->flow->id());
$cache_item_data = $cache_item ? $cache_item->data : NULL;
if ($cache_item_data && isset($cache_item_data->entityTypeConfigs)) {
$cache[$this->flow->id()] = $cache_item_data->entityTypeConfigs;
// When asking for NEW versions, we can't rely on the cache as entity
// types and fields may change any time.
$cache[$this->flow->id()]['new'] = NULL;
unset($cache[$this->flow->id()]['new']);
}
}
// Already exists in cache.
if (!empty($cache[$this->flow->id()][$version_index])) {
return $cache[$this->flow->id()][$version_index];
}
$settings = $this->flow->simple_settings;
$is_push = Flow::TYPE_PUSH === $this->flow->type;
$merge_local_changes = $settings['mergeLocalChanges'];
$selected_pools = [];
$selected_pools_manual_assignment = [];
$auto_assign_pools = self::ASSIGN_ALL_POOLS === $settings['poolAssignment'];
$used_pools = $this->getUsedPools();
$pools = Pool::getAll();
foreach ($pools as $id => $pool) {
if (isset($used_pools[$id])) {
$selected_pools_manual_assignment[$id] = Pool::POOL_USAGE_ALLOW;
if ($auto_assign_pools) {
$selected_pools[$id] = Pool::POOL_USAGE_FORCE;
}
else {
$selected_pools[$id] = Pool::POOL_USAGE_ALLOW;
}
}
else {
$selected_pools[$id] = Pool::POOL_USAGE_FORBID;
}
}
$entity_plugin_manager = \Drupal::service('plugin.manager.cms_content_sync_entity_handler');
$field_plugin_manager = \Drupal::service('plugin.manager.cms_content_sync_field_handler');
$entity_field_manager = \Drupal::service('entity_field.manager');
$field_map = $entity_field_manager->getFieldMap();
$entity_types = \Drupal::service('entity_type.bundle.info')->getAllBundleInfo();
$entity_type_versions = $this->getExportedEntityTypeVersions();
$assign_pools_manually_to_dependencies = empty($settings['assignPoolsManuallyToDependencies']) ? [] : $settings['assignPoolsManuallyToDependencies'];
foreach ($entity_types as $entity_type_name => $bundles) {
if (empty($settings['entityTypeSettings'][$entity_type_name])) {
continue;
}
foreach ($bundles as $bundle_name => $entity_bundle) {
$info = EntityHandlerPluginManager::getEntityTypeInfo($entity_type_name, $bundle_name);
if (!empty($info['no_entity_type_handler']) || !empty($info['required_field_not_supported'])) {
continue;
}
if (!empty($settings['entityTypeSettings'][$entity_type_name]['allBundles'])) {
$bundle_settings = $settings['entityTypeSettings'][$entity_type_name]['allBundles'];
}
elseif (!empty($settings['entityTypeSettings'][$entity_type_name]['perBundle'][$bundle_name])) {
$bundle_settings = $settings['entityTypeSettings'][$entity_type_name]['perBundle'][$bundle_name];
}
else {
continue;
}
if (self::MODE_IGNORE === $bundle_settings['mode']) {
continue;
}
if (self::MODE_DEFAULT === $bundle_settings['mode']) {
$mode = $settings['mode'];
}
else {
$mode = $bundle_settings['mode'];
}
$deletion_key = self::MODE_DEPENDENT === $mode ? 'embeddedDeletions' : 'deletions';
$entity_handlers = $entity_plugin_manager->getHandlerOptions($entity_type_name, $bundle_name, TRUE);
if (!count($entity_handlers)) {
continue;
}
$entity_handler_names = array_keys($entity_handlers);
$handler_id = reset($entity_handler_names);
$pool_assignment = in_array($entity_type_name, $assign_pools_manually_to_dependencies) ? $selected_pools_manual_assignment : $selected_pools;
$restrict_menus = NULL;
if (!empty($bundle_settings['filters'])) {
foreach ($bundle_settings['filters'] as $filter) {
if ('menu' === $filter['type']) {
$restrict_menus = array_map(function ($menu) {
return $menu->label();
}, Menu::loadMultiple());
foreach ($restrict_menus as $menu_machine_name => $menu_label) {
$restrict_menus[$menu_machine_name] = in_array($menu_machine_name, $filter['values']) ? 1 : 0;
}
break;
}
}
}
$result[$entity_type_name][$bundle_name] = [
'version' => $include_new_versions || $this->virtual ? Flow::getEntityTypeVersion($entity_type_name, $bundle_name) : (empty($entity_type_versions[$entity_type_name][$bundle_name]) ? NULL : $entity_type_versions[$entity_type_name][$bundle_name]),
'handler' => $handler_id,
'handler_settings' => [
'ignore_unpublished' => $settings['ignoreUnpublishedChanges'] ? 1 : 0,
'allow_explicit_unpublishing' => $settings['allowExplicitUnpublishing'] ? 1 : 0,
'export_menu_items' => $settings['pushMenuItems'] ? 1 : 0,
'export_crop' => 1,
'restrict_menus' => $restrict_menus,
],
'export' => $is_push ? $mode : self::MODE_IGNORE,
'export_pools' => $is_push ? $pool_assignment : [],
'export_deletion_settings' => [
'export_deletion' => empty($settings[$deletion_key]) ? 0 : 1,
],
'pool_export_widget_type' => $settings['poolSelectionWidget'],
'preview' => $settings['pushPreviews'] && !empty($settings['entityTypeSettings'][$entity_type_name]['perBundle'][$bundle_name]['previewViewMode']) ? $settings['entityTypeSettings'][$entity_type_name]['perBundle'][$bundle_name]['previewViewMode'] : Flow::PREVIEW_DISABLED,
'import' => $is_push ? self::MODE_IGNORE : $mode,
'import_pools' => $is_push ? [] : $selected_pools,
'import_deletion_settings' => [
'import_deletion' => empty($settings[$deletion_key]) ? 0 : 1,
'allow_local_deletion_of_import' => empty($settings['allowLocalDeletion']) ? 0 : 1,
],
'import_updates' => $settings['updateBehavior'],
'allow_cross_sync' => !empty($settings['allowCrossSync']),
'properties' => [],
];
$handler = $entity_plugin_manager->createInstance($handler_id, [
'entity_type_name' => $entity_type_name,
'bundle_name' => $bundle_name,
'settings' => $result[$entity_type_name][$bundle_name]['handler_settings'],
'sync' => NULL,
]);
if (isset($field_map[$entity_type_name])) {
$forbidden_fields = $handler->getForbiddenFields();
$pools = Pool::getAll();
if (count($pools)) {
try {
$reserved = reset($pools)
->getClient()
->getReservedPropertyNames();
$forbidden_fields = array_merge($forbidden_fields, $reserved);
}
// The site may not be registered yet. In that case we
// don't need reliable settings anyway as the user can't
// push.
catch (\Exception $e) {
}
}
$fields = $entity_field_manager->getFieldDefinitions($entity_type_name, $bundle_name);
foreach ($fields as $key => $field) {
$field_handlers = $field_plugin_manager->getHandlerOptions($entity_type_name, $bundle_name, $key, $field, TRUE);
$ignore = in_array($key, $forbidden_fields) || empty($field_handlers);
$handler_id = $ignore ? 'ignore' : key($field_handlers);
// TODO: Merge & Use EntityReferenceHandlerBase::getReferencedEntityTypesFromFieldDefinition consistently.
$referenced_type = NULL;
if (in_array($field->getType(), [
'entity_reference',
'entity_reference_revisions',
'cohesion_entity_reference_revisions',
'webform',
])) {
$referenced_type = $field->getSetting('target_type');
}
elseif (in_array($field->getType(), ['image', 'file', 'file_uri'])) {
$referenced_type = 'file';
}
elseif (in_array($field->getType(), ['bricks'])) {
$referenced_type = 'brick';
}
$is_dynamic_reference = 'dynamic_entity_reference' === $field->getType();
// Virtual Flows are meant to serialize one entity at run-time without an existing Flow present and ignore any dependencies.
if ($this->virtual) {
$push_referenced_entities = FALSE;
}
// If the referenced entity type is meant to be assigned a Pool manually, we ignore it (available for paragraphs).
elseif (in_array($referenced_type, $assign_pools_manually_to_dependencies)) {
$push_referenced_entities = FALSE;
}
// If there's no static type AND no dynamic type, we ignore it.
elseif (!$referenced_type) {
$push_referenced_entities = $is_dynamic_reference;
}
// If the referenced entity type has not been configured at all, we ignore it.
elseif (empty($settings['entityTypeSettings'][$referenced_type])) {
$push_referenced_entities = FALSE;
}
// Now it's getting a bit more complicated as a field may reference multiple bundles and users can select differenct behavior
// for different bundles.
else {
// All bundles are configured the same- easy to resolve.
if (!empty($settings['entityTypeSettings'][$referenced_type]['allBundles'])) {
// Dependent entities are meant to be added as dependencies.
if (self::MODE_DEPENDENT === $settings['entityTypeSettings'][$referenced_type]['allBundles']['mode']) {
$push_referenced_entities = TRUE;
}
// Independent entities are not added as dependencies.
// Ignored entities are not added as dependencies.
else {
$push_referenced_entities = FALSE;
}
}
// Bundles are configured separately.
else {
// Check if any bundle is configured as dependent. If any is, we set the flag to push the referenced entity.
// If none is, we ignore it (default). If the PushIntent is asked to embed an entity that is exported independently,
// it will not be embedded but added as a dependency instead.
$push_referenced_entities = FALSE;
foreach ($settings['entityTypeSettings'][$referenced_type]['perBundle'] as $referenced_bundle => $referenced_bundle_settings) {
if (self::MODE_DEPENDENT === $referenced_bundle_settings['mode']) {
$push_referenced_entities = TRUE;
break;
}
}
}
}
$subscribe_only_to = NULL;
if (!empty($settings['entityTypeSettings'][$entity_type_name]['perBundle'][$bundle_name]['filters'])) {
foreach ($settings['entityTypeSettings'][$entity_type_name]['perBundle'][$bundle_name]['filters'] as $filter) {
if ('includes-reference' === $filter['type'] && $filter['fieldMachineName'] === $key) {
$subscribe_only_to = [];
foreach ($filter['values'] as $value) {
$subscribe_only_to[] = [
'type' => $value['namespaceMachineName'],
'bundle' => $value['machineName'],
'uuid' => $value['remoteUuid'],
];
}
}
}
}
$field_settings = [
'handler' => $handler_id,
'export' => NULL,
'import' => NULL,
'preview' => NULL,
'entity_type' => $entity_type_name,
'entity_bundle' => $bundle_name,
'handler_settings' => [
'identification' => $settings['resolveUserReferences'],
'export_referenced_custom_blocks' => 1,
'export_referenced_entities' => $push_referenced_entities ? 1 : 0,
'merge_local_changes' => 'paragraph' === $referenced_type && $merge_local_changes ? 1 : 0,
'subscribe_only_to' => $subscribe_only_to,
],
];
if (!$ignore) {
/**
* @var \Drupal\cms_content_sync\Plugin\FieldHandlerInterface $handler
*/
$handler = $field_plugin_manager->createInstance($handler_id, [
'entity_type_name' => $entity_type_name,
'bundle_name' => $bundle_name,
'field_name' => $key,
'field_definition' => $field,
'settings' => $field_settings,
'sync' => $this->flow,
]);
$allowed_push_options = $handler->getAllowedPushOptions();
if ($is_push && in_array(PushIntent::PUSH_AUTOMATICALLY, $allowed_push_options)) {
$field_settings['export'] = PushIntent::PUSH_AUTOMATICALLY;
}
$allowed_pull_options = $handler->getAllowedPullOptions();
if (!$is_push && in_array(PullIntent::PULL_AUTOMATICALLY, $allowed_pull_options)) {
$field_settings['import'] = PullIntent::PULL_AUTOMATICALLY;
}
}
$result[$entity_type_name][$bundle_name]['properties'][$key] = $field_settings;
}
}
}
}
$cache[$this->flow->id()][$version_index] = $result;
if (!$include_new_versions && !$this->isVirtual()) {
if (!$cache_item_data) {
$cache_item_data = new \stdClass();
}
$cache_item_data->entityTypeConfigs = $cache[$this->flow->id()];
unset($cache_item_data->entityTypeConfigs['new']);
$drupal_cache->set(Flow::CACHE_ITEM_NAME_FLOWS . '/' . $this->flow->id(), $cache_item_data, CacheBackendInterface::CACHE_PERMANENT, [Flow::CACHE_TAG_ANY_FLOW]);
}
return $cache[$this->flow->id()][$version_index];
}
/**
* Get the exported entity type version.
*
* @return string
* Returns the exported entity type version.
*/
protected function getExportedEntityTypeVersions() {
$status = \Drupal::state()->get('cms_content_sync.flow_status_' . $this->flow->id);
if (empty($status)) {
return [];
}
return $status['entity_type_versions'];
}
/**
* Get the flows form configuration.
*/
protected static function getFormConfig(?Flow $flow) {
$all_pools = Pool::getAll();
$pools = [];
foreach ($all_pools as $pool) {
$pools[] = [
'name' => $pool->label(),
'machineName' => $pool->id(),
];
}
$all_flows = Flow::getAll(TRUE);
$reserved_flows = [];
$pushed_bundles = [];
$pulled_bundles = [];
$pushed_pools = [];
$pulled_pools = [];
foreach ($all_flows as $flow_item) {
if ($flow && $flow->id === $flow_item->id) {
continue;
}
$reserved_flows[] = $flow_item->id;
foreach ($flow_item->getController()->getEntityTypeConfig() as $entity_type_name => $bundles) {
foreach ($bundles as $bundle_name => $settings) {
$bundle = [
'namespaceMachineName' => (string) $entity_type_name,
'machineName' => (string) $bundle_name,
];
if (PushIntent::PUSH_AUTOMATICALLY === $settings['export'] || PushIntent::PUSH_MANUALLY === $settings['export']) {
if (!in_array($bundle, $pushed_bundles)) {
$pushed_bundles[] = $bundle;
}
foreach ($settings['export_pools'] as $pool_id => $pool_mode) {
if (Pool::POOL_USAGE_FORBID !== $pool_mode && !in_array($pool_id, $pushed_pools)) {
$pushed_pools[] = $pool_id;
}
}
}
if (PullIntent::PULL_AUTOMATICALLY === $settings['import'] || PullIntent::PULL_MANUALLY === $settings['import']) {
if (!in_array($bundle, $pulled_bundles)) {
$pulled_bundles[] = $bundle;
}
foreach ($settings['import_pools'] as $pool_id => $pool_mode) {
if (Pool::POOL_USAGE_FORBID !== $pool_mode && !in_array($pool_id, $pulled_pools)) {
$pulled_pools[] = $pool_id;
}
}
}
}
}
}
$bundles = [];
$entity_types = \Drupal::service('entity_type.bundle.info')->getAllBundleInfo();
$entity_field_manager = \Drupal::service('entity_field.manager');
$display_modes = \Drupal::service('entity_type.manager')
->getStorage('entity_view_display')
->loadMultiple();
foreach ($entity_types as $entity_type_machine_name => $type_bundles) {
foreach ($type_bundles as $bundle_machine_name => $bundle) {
// Always ignore webform submissions as they will not even provide a
// correct machine name (using numbers).
if ('webform_submission' === $entity_type_machine_name) {
continue;
}
$info = EntityHandlerPluginManager::getEntityTypeInfo($entity_type_machine_name, $bundle_machine_name);
$display_modes_ids = array_keys($display_modes);
$available_preview_modes = [];
foreach ($display_modes_ids as $id) {
$length = strlen($entity_type_machine_name) + strlen($bundle_machine_name) + 2;
if (substr($id, 0, $length) != $entity_type_machine_name . '.' . $bundle_machine_name . '.') {
continue;
}
$id = substr($id, $length);
$label = $id;
$available_preview_modes[$id] = $label;
}
$missing_fields = array_merge($info['unsupported_required_fields'] ?? [], $info['unsupported_optional_fields'] ?? []);
$reference_fields = [];
if (EntityHandlerPluginManager::isEntityTypeFieldable($entity_type_machine_name)) {
/**
* @var \Drupal\Core\Field\FieldDefinitionInterface[] $fields
*/
$fields = $entity_field_manager->getFieldDefinitions($entity_type_machine_name, $bundle_machine_name);
/** Drupal\Core\Field\BaseFieldDefinition $field */
foreach ($fields as $key => $field) {
$referenced_type = NULL;
$referenced_bundles = NULL;
if (in_array($field->getType(), [
'entity_reference',
'entity_reference_revisions',
'webform',
])) {
$referenced_type = $field->getSetting('target_type');
}
elseif (in_array($field->getType(), ['image', 'file', 'file_uri'])) {
$referenced_type = 'file';
}
elseif (in_array($field->getType(), ['bricks'])) {
$referenced_type = 'brick';
}
if (!$referenced_type) {
continue;
}
$item = [
'machineName' => (string) $key,
'name' => empty($field->getLabel()) ? $key : $field->getLabel(),
'targetNamespaceMachineName' => (string) $referenced_type,
];
$field_settings = $field->getSettings();
if ((!empty($field_settings['handler_settings']) || 'brick' === $referenced_type) && !empty($field_settings['handler_settings']['target_bundles'])) {
/** @var \Drupal\cms_content_sync\Helper\FieldHelper $field_helper */
$field_helper = \Drupal::service('cms_content_sync.field_helper');
$item['targetMachineNames'] = $field_helper->getEntityReferenceFieldAllowedTargetBundles($field);
}
$reference_fields[] = $item;
}
}
$menus = NULL;
if ('menu_link_content' === $entity_type_machine_name) {
$menus = [];
if ($custom_menus = Menu::loadMultiple()) {
foreach ($custom_menus as $menu_machine_name => $menu) {
$menus[$menu_machine_name] = $menu->label();
}
}
}
$bundles[] = [
'namespaceMachineName' => (string) $entity_type_machine_name,
'machineName' => (string) $bundle_machine_name,
'name' => $bundle['label'],
'supported' => $info['is_supported'],
'isConfiguration' => EntityHandlerPluginManager::isEntityTypeConfiguration($entity_type_machine_name),
'viewModes' => $available_preview_modes,
'unsupportedFields' => $missing_fields,
'referenceFields' => $reference_fields,
'menus' => $menus,
];
}
}
$language_instances = \Drupal::languageManager()->getLanguages();
$languages = [];
foreach ($language_instances as $language) {
$languages[] = [
'id' => $language->getId(),
'name' => $language->getName(),
];
}
return [
'bundles' => $bundles,
'pools' => $pools,
'reservedFlowMachineNames' => $reserved_flows,
'pushedEntityTypes' => $pushed_bundles,
'pulledEntityTypes' => $pulled_bundles,
'pushedPools' => $pushed_pools,
'pulledPools' => $pulled_pools,
'languages' => $languages,
];
}
}
