private function SyncCoreEntityItemResource::handleIncomingEntity in CMS Content Sync 2.1.x
Same name and namespace in other branches
- 2.0.x src/Plugin/rest/resource/SyncCoreEntityItemResource.php \Drupal\cms_content_sync\Plugin\rest\resource\SyncCoreEntityItemResource::handleIncomingEntity()
2 calls to SyncCoreEntityItemResource::handleIncomingEntity()
- SyncCoreEntityItemResource::delete in src/
Plugin/ rest/ resource/ SyncCoreEntityItemResource.php - SyncCoreEntityItemResource::post in src/
Plugin/ rest/ resource/ SyncCoreEntityItemResource.php
File
- src/
Plugin/ rest/ resource/ SyncCoreEntityItemResource.php, line 328
Class
- SyncCoreEntityItemResource
- Provides entity interfaces for Content Sync, allowing Sync Core v2 to request and manipulate entities.
Namespace
Drupal\cms_content_sync\Plugin\rest\resourceCode
private function handleIncomingEntity($flow_id, $entity_type_name, $entity_bundle, $shared_entity_id, array $data, $action) {
$flow = Flow::getAll()[$flow_id];
if (empty($flow)) {
$message = t("The flow @flow_id doesn't exist.", [
'@flow_id' => $flow_id,
])
->render();
\Drupal::logger('cms_content_sync')
->notice('@not PULL @action @shared_entity_id: @message', [
'@action' => $action,
'@shared_entity_id' => $shared_entity_id,
'@not' => 'NO',
'@message' => $message,
]);
return $this
->respondWith([
'message' => $message,
], self::CODE_NOT_FOUND, SyncIntent::ACTION_DELETE == $action);
}
\Drupal::logger('cms_content_sync')
->notice('received @shared_entity_id via @flow_id with @body', [
'@shared_entity_id' => $shared_entity_id,
'@flow_id' => $flow_id,
'@body' => json_encode($data, JSON_PRETTY_PRINT),
]);
$reason = PullIntent::PULL_FORCED;
$core = SyncCoreFactory::getSyncCoreV2();
$all_pools = Pool::getAll();
$pools = [];
$operation = $core
->getSyndicationService()
->handlePull($flow->id, null, null, $data, SyncIntent::ACTION_DELETE === $action);
$entity_type_name = $operation
->getEntityTypeNamespaceMachineName();
$entity_bundle = $operation
->getEntityTypeMachineName();
$entity_type_version = $operation
->getEntityTypeVersionId();
if (EntityHandlerPluginManager::isEntityTypeConfiguration($entity_type_name)) {
$entity_uuid = \Drupal::entityTypeManager()
->getStorage($entity_type_name)
->load($operation
->getId())
->uuid();
}
else {
$entity_uuid = $shared_entity_id;
}
// Delete doesn't come with pools
$pool_machine_names = $operation
->getPoolIds();
if (empty($pool_machine_names)) {
$pool_machine_names = [];
$statuses = EntityStatus::getInfosForEntity($operation
->getEntityTypeNamespaceMachineName(), $entity_uuid, [
'flow' => $flow_id,
]);
// Maybe the entity type is overloaded (multiple Flows for the same type) and the Sync Core uses a
// different Flow for the delete request because none of the Flows matches.
if (empty($statuses)) {
$statuses = EntityStatus::getInfosForEntity($operation
->getEntityTypeNamespaceMachineName(), $entity_uuid);
}
foreach ($statuses as $status) {
$pool_machine_names[] = $status
->getPool()
->id();
}
\Drupal::logger('cms_content_sync')
->notice(json_encode([
$operation
->getEntityTypeNamespaceMachineName(),
$entity_uuid,
$flow_id,
count($statuses),
$pool_machine_names,
]));
}
// TODO: Handle multiple Pools at once.
foreach ($pool_machine_names as $machine_name) {
if (!isset($all_pools[$machine_name])) {
$message = t("The pool @machine_name doesn't exist.", [
'@machine_name' => $machine_name,
])
->render();
\Drupal::logger('cms_content_sync')
->notice('@not PULL @action @shared_entity_id: @message', [
'@action' => $action,
'@shared_entity_id' => $shared_entity_id,
'@not' => 'NO',
'@message' => $message,
]);
$this
->saveFailedPull($machine_name, $entity_type_name, $entity_bundle, $entity_type_version, $entity_uuid, PullIntent::PULL_FAILED_UNKNOWN_POOL, $action, $reason);
return $this
->respondWith([
'message' => $message,
], self::CODE_NOT_FOUND, SyncIntent::ACTION_DELETE == $action);
}
$pools[] = $all_pools[$machine_name];
}
if (empty($pools)) {
return $this
->respondWith([
'message' => "No pools were given and the entity doesn't exist on this site with any pool.",
], 404, SyncIntent::ACTION_DELETE == $action);
}
try {
$intent = new PullIntent($flow, $pools[0], $reason, $action, $entity_type_name, $entity_bundle, $operation);
$status = $intent
->execute();
$parent = $intent
->getEntity();
$parent_type = $parent ? $parent
->getEntityTypeId() : null;
$parent_uuid = $parent ? $parent
->uuid() : null;
while ($embed = $operation
->getNextUnprocessedEmbed()) {
$embed_pool = null;
foreach ($embed
->getPoolIds() as $pool_id) {
if (isset($all_pools[$pool_id])) {
$embed_pool = $all_pools[$pool_id];
break;
}
}
if (!$embed_pool) {
continue;
}
$embed_intent = new PullIntent($flow, $embed_pool, $reason, $action, $embed
->getEntityTypeNamespaceMachineName(), $embed
->getEntityTypeMachineName(), $embed, $parent_type, $parent_uuid);
$embed_intent
->execute();
}
// Delete menu items that no longer exist.
if ($parent) {
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
/**
* @var Drupal\menu_link_content\Plugin\Menu\MenuLinkContent[] $menu_items
*/
$menu_items = $menu_link_manager
->loadLinksByRoute('entity.' . $parent_type . '.canonical', [
$parent_type => $parent
->id(),
]);
foreach ($menu_items as $plugin_item) {
/**
* @var Drupal\menu_link_content\Entity\MenuLinkContent $item
*/
// We need to get an Entity at this point,
// but 'getEntity' is protected for some reason.
// So we don't have other choice here but use a reflection.
$menu_link_reflection = new \ReflectionMethod('\\Drupal\\menu_link_content\\Plugin\\Menu\\MenuLinkContent', 'getEntity');
$menu_link_reflection
->setAccessible(true);
$item = $menu_link_reflection
->invoke($plugin_item, 'getEntity');
if (!$operation
->isEmbedded($item
->getEntityTypeId(), $item
->uuid())) {
$menu_pools = [];
$statuses = EntityStatus::getInfosForEntity($item
->getEntityTypeId(), $item
->uuid(), [
'flow' => $flow_id,
]);
foreach ($statuses as $status) {
if (!$status
->getLastPull() || !$status
->wasPulledEmbedded()) {
continue;
}
$menu_pools[] = $status
->getPool();
}
if (empty($menu_pools)) {
continue;
}
$menu_operation = new class($item) {
/**
* @var Drupal\menu_link_content\Entity\MenuLinkContent
*/
protected $item;
public function __construct($item) {
$this->item = $item;
}
public function getUuid() {
return $this->item
->uuid();
}
public function getSourceUrl() {
return '';
}
public function getUsedTranslationLanguages() {
return [];
}
public function getName() {
return $this->item
->label();
}
public function getProperty($name) {
try {
return $this->item
->get($name)
->getValue();
} catch (\Exception $e) {
return null;
}
}
};
$menu_intent = new PullIntent($flow, $menu_pools[0], PullIntent::PULL_FORCED, SyncIntent::ACTION_DELETE, $item
->getEntityTypeId(), $item
->bundle(), $menu_operation, $parent_type, $parent_uuid);
$menu_intent
->execute();
}
}
}
if (!Migration::alwaysUseV2()) {
Migration::entityUsedV2($flow->id, $entity_type_name, $entity_bundle, $entity_uuid, EntityHandlerPluginManager::isEntityTypeConfiguration($entity_type_name) ? $shared_entity_id : null, false);
}
} catch (SyncException $e) {
$message = $e->parentException ? $e->parentException
->getMessage() : ($e->errorCode == $e
->getMessage() ? '' : $e
->getMessage());
if ($message) {
$message = t('Internal error @code: @message', [
'@code' => $e->errorCode,
'@message' => $message,
])
->render();
}
else {
$message = t('Internal error @code', [
'@code' => $e->errorCode,
])
->render();
}
\Drupal::logger('cms_content_sync')
->error('@not PULL @action @entity_type:@bundle @uuid @reason: @message' . "\n" . '@trace' . "\n" . '@request_body<br>Flow: @flow_id | Pool: @pool_id', [
'@reason' => $reason,
'@action' => $action,
'@entity_type' => $entity_type_name,
'@bundle' => $entity_bundle,
'@uuid' => $entity_uuid,
'@not' => 'NO',
'@flow_id' => $flow_id,
'@pool_id' => $pools[0]
->id(),
'@message' => $message,
'@trace' => ($e->parentException ? $e->parentException
->getTraceAsString() . "\n\n\n" : '') . $e
->getTraceAsString(),
'@request_body' => json_encode($data),
]);
$this
->saveFailedPull($pools[0]
->id(), $entity_type_name, $entity_bundle, $entity_type_version, $entity_uuid, PullIntent::PULL_FAILED_CONTENT_SYNC_ERROR, $action, $reason, $flow->id);
return $this
->respondWith([
'message' => t('SyncException @code: @message', [
'@code' => $e->errorCode,
'@message' => $e
->getMessage(),
])
->render(),
'code' => $e->errorCode,
], 500, SyncIntent::ACTION_DELETE == $action);
} catch (\Exception $e) {
$message = $e
->getMessage();
\Drupal::logger('cms_content_sync')
->error('@not PULL @action @entity_type:@bundle @uuid @reason: @message' . "\n" . '@trace' . "\n" . '@request_body<br>Flow: @flow_id | Pool: @pool_id', [
'@reason' => $reason,
'@action' => $action,
'@entity_type' => $entity_type_name,
'@bundle' => $entity_bundle,
'@uuid' => $entity_uuid,
'@not' => 'NO',
'@flow_id' => $flow_id,
'@pool_id' => $pools[0]
->id(),
'@message' => $message,
'@trace' => $e
->getTraceAsString(),
'@request_body' => json_encode($data),
]);
$this
->saveFailedPull($pools[0]->id, $entity_type_name, $entity_bundle, $entity_type_version, $entity_uuid, PullIntent::PULL_FAILED_INTERNAL_ERROR, $action, $reason, $flow->id);
return $this
->respondWith([
'message' => t('Unexpected error: @message', [
'@message' => $e
->getMessage(),
])
->render(),
], 500, SyncIntent::ACTION_DELETE == $action);
}
if (!$status) {
$this
->saveFailedPull($pools[0]->id, $entity_type_name, $entity_bundle, $entity_type_version, $entity_uuid, PullIntent::PULL_FAILED_HANDLER_DENIED, $action, $reason, $flow->id);
}
if ($status) {
$url = SyncIntent::ACTION_DELETE === $action ? null : $intent
->getViewUrl();
$response_body = $operation
->getResponseBody($url);
// If we send data for DELETE requests, the Drupal Serializer will throw
// a random error. So we just leave the body empty then.
return $this
->respondWith($response_body, 200, SyncIntent::ACTION_DELETE == $action);
}
return $this
->respondWith([
'message' => t('Entity is not configured to be pulled yet.')
->render(),
], 404, SyncIntent::ACTION_DELETE == $action);
}