class PullEntity in CMS Content Sync 8
Same name and namespace in other branches
- 2.1.x src/Plugin/rest/resource/PullEntity.php \Drupal\cms_content_sync\Plugin\rest\resource\PullEntity
- 2.0.x src/Plugin/rest/resource/PullEntity.php \Drupal\cms_content_sync\Plugin\rest\resource\PullEntity
Provides entity interfaces for Content Sync, allowing the manual pull dashboard to query preview entities and to pull them to the site.
Plugin annotation
@RestResource(
id = "cms_content_sync_import_entity",
label = @Translation("Content Sync Pull"),
uri_paths = {
"canonical" = "/rest/cms-content-sync-import/{pool_id}",
"create" = "/rest/cms-content-sync-import/{pool_id}/{entity_type_name}/{bundle_name}/{shared_entity_id}"
}
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\rest\Plugin\ResourceBase implements ContainerFactoryPluginInterface, ResourceInterface
- class \Drupal\cms_content_sync\Plugin\rest\resource\PullEntity
- class \Drupal\rest\Plugin\ResourceBase implements ContainerFactoryPluginInterface, ResourceInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of PullEntity
File
- src/
Plugin/ rest/ resource/ PullEntity.php, line 33
Namespace
Drupal\cms_content_sync\Plugin\rest\resourceView source
class PullEntity extends ResourceBase {
/**
* @var int CODE_INVALID_DATA The provided data could not be interpreted
*/
public const CODE_INVALID_DATA = 401;
/**
* @var int CODE_NOT_FOUND The entity doesn't exist or can't be accessed
*/
public const CODE_NOT_FOUND = 404;
/**
* @var int CODE_UNEXPECTED_ERROR The Sync Core wasn't able to synchronize this entity
*/
public const CODE_UNEXPECTED_ERROR = 500;
/**
* @var \Drupal\Core\Entity\EntityTypeBundleInfo
*/
protected $entityTypeBundleInfo;
/**
* @var \Drupal\Core\Entity\EntityTypeManager
*/
protected $entityTypeManager;
/**
* @var \Drupal\Core\Render\Renderer
*/
protected $renderedManager;
/**
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* Constructs an object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance
* @param string $plugin_id
* The plugin_id for the plugin instance
* @param mixed $plugin_definition
* The plugin implementation definition
* @param array $serializer_formats
* The available serialization formats
* @param \Psr\Log\LoggerInterface $logger
* A logger instance
* @param \Drupal\Core\Entity\EntityTypeBundleInfo $entity_type_bundle_info
* An entity type bundle info instance
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* An entity type manager instance
* @param \Drupal\Core\Render\Renderer $render_manager
* A rendered instance
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository interface
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, EntityTypeBundleInfo $entity_type_bundle_info, EntityTypeManagerInterface $entity_type_manager, Renderer $render_manager, EntityRepositoryInterface $entity_repository) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
$this->entityTypeBundleInfo = $entity_type_bundle_info;
$this->entityTypeManager = $entity_type_manager;
$this->renderedManager = $render_manager;
$this->entityRepository = $entity_repository;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->getParameter('serializer.formats'), $container
->get('logger.factory')
->get('rest'), $container
->get('entity_type.bundle.info'), $container
->get('entity_type.manager'), $container
->get('renderer'), $container
->get('entity.repository'));
}
/**
* Responds to entity GET requests.
*
* @param string $pool_id
* The ID of the selected flow
*
* @throws \Exception
*
* @return \Symfony\Component\HttpFoundation\Response
* A list of entities of the given type and bundle
*/
public function get(string $pool_id) {
$cache_build = [
'#cache' => [
'max-age' => 0,
],
];
// Loaded directly from the Sync Core, so we just need to provide the status for them.
if (!empty($_GET['entities'])) {
$items = [];
$types = explode(';', $_GET['entities']);
foreach ($types as $type) {
list($type, $ids) = explode(':', $type);
$ids = explode(',', $ids);
foreach ($ids as $id) {
list(, , $entity_type_name, $bundle_name) = explode('-', $type);
$items[] = array_merge([
'entity_type_id' => $type,
'id' => $id,
], $this
->getPreviewItemData($entity_type_name, $bundle_name, $id));
}
}
$resource_response = new ResourceResponse([
'items' => $items,
]);
$resource_response
->addCacheableDependency($cache_build);
return $resource_response;
}
$pool = Pool::getAll()[$pool_id];
if (!$pool) {
$resource_response = new ResourceResponse([
'message' => "Unknown pool {$pool_id}.",
], self::CODE_NOT_FOUND);
$resource_response
->addCacheableDependency($cache_build);
return $resource_response;
}
$entity_type_ids = [];
$entity_type_name = isset($_GET['entity_type_name']) ? $_GET['entity_type_name'] : null;
$bundle_name = isset($_GET['bundle_name']) ? $_GET['bundle_name'] : null;
$page = isset($_GET['page']) ? intval($_GET['page']) : 0;
$sync_core_settings = $pool
->getClient()
->getSyndicationService()
->configurePullDashboard();
/**
* @var \Drupal\Core\Entity\EntityFieldManager $entityFieldManager
*/
$entityFieldManager = \Drupal::service('entity_field.manager');
foreach (Flow::getAll() as $flow) {
foreach ($flow
->getEntityTypeConfig() as $definition) {
if (!$flow
->canPullEntity($definition['entity_type_name'], $definition['bundle_name'], PullIntent::PULL_MANUALLY)) {
continue;
}
if ($entity_type_name && $definition['entity_type_name'] != $entity_type_name) {
continue;
}
if ($bundle_name && $definition['bundle_name'] != $bundle_name) {
continue;
}
if (empty($definition['import_pools'][$pool->id]) || Pool::POOL_USAGE_ALLOW != $definition['import_pools'][$pool->id]) {
continue;
}
if (isset($entity_type_ids[$pool_id][$definition['entity_type_name']][$definition['bundle_name']])) {
continue;
}
if (EntityHandlerPluginManager::isEntityTypeFieldable($definition['entity_type_name'])) {
/**
* @var \Drupal\Core\Field\FieldDefinitionInterface[] $fields
*/
$fields = $entityFieldManager
->getFieldDefinitions($definition['entity_type_name'], $definition['bundle_name']);
foreach ($fields as $key => $field) {
$field_config = $flow
->getFieldHandlerConfig($definition['entity_type_name'], $definition['bundle_name'], $key);
if (empty($field_config)) {
continue;
}
if (empty($field_config['handler_settings']['subscribe_only_to'])) {
continue;
}
$allowed = [];
foreach ($field_config['handler_settings']['subscribe_only_to'] as $ref) {
$allowed[] = $ref['uuid'];
}
$sync_core_settings
->ifTaggedWith($pool_id, $definition['entity_type_name'], $definition['bundle_name'], $key, $allowed);
}
}
$sync_core_settings
->forEntityType($pool_id, $definition['entity_type_name'], $definition['bundle_name']);
$entity_type_ids[$pool_id][$definition['entity_type_name']][$definition['bundle_name']] = true;
}
}
if (empty($entity_type_ids)) {
$resource_response = new ResourceResponse([
'message' => 'No previews available.',
], self::CODE_NOT_FOUND);
$resource_response
->addCacheableDependency($cache_build);
return $resource_response;
}
if (!empty($_GET['filter_title'])) {
$sync_core_settings
->searchInTitle($_GET['filter_title']);
}
if (!empty($_GET['filter_preview'])) {
$sync_core_settings
->searchInPreview($_GET['filter_preview']);
}
$sync_core_settings
->publishedBetween(empty($_GET['filter_published_from']) ? null : (int) $_GET['filter_published_from'], empty($_GET['filter_published_to']) ? null : (int) $_GET['filter_published_to'] + 24 * 60 * 60);
try {
$order_by_title = isset($_GET['order_by']) && 'title' == $_GET['order_by'];
$order_ascending = isset($_GET['order_direction']) && 'asc' == $_GET['order_direction'];
$response = $sync_core_settings
->runSearch($order_by_title, $order_ascending, $page);
} catch (SyncCoreException $e) {
$body = $e
->getResponseBody();
$code = $e
->getStatusCode();
$resource_response = new ResourceResponse($body ? $body : json_encode([
'message' => $e
->getMessage(),
]), $code ? $code : 500);
$resource_response
->addCacheableDependency($cache_build);
return $resource_response;
}
foreach ($response
->getItems() as $item) {
$item
->extend($this
->getPreviewItemData($item
->getType(), $item
->getBundle(), $item
->getId()));
}
$resource_response = new ResourceResponse($response
->toArray());
$resource_response
->addCacheableDependency($cache_build);
return $resource_response;
}
/**
* Responds to entity POST requests.
*
* @throws \Exception
*
* @return \Symfony\Component\HttpFoundation\Response
* -
*/
public function post(string $pool_id, string $entity_type_name, string $bundle_name, string $shared_entity_id) {
$pool = Pool::getAll()[$pool_id];
if (!$pool) {
return new ResourceResponse([
'message' => "Unknown pool ID {$pool_id}.",
], self::CODE_NOT_FOUND);
}
$preview_item = null;
foreach (Flow::getAll() as $flow) {
foreach ($flow
->getEntityTypeConfig() as $definition) {
if (!$flow
->canPullEntity($definition['entity_type_name'], $definition['bundle_name'], PullIntent::PULL_MANUALLY)) {
continue;
}
if ($definition['entity_type_name'] != $entity_type_name) {
continue;
}
if ($definition['bundle_name'] != $bundle_name) {
continue;
}
if (Pool::POOL_USAGE_ALLOW != $definition['import_pools'][$pool->id]) {
continue;
}
try {
$preview_item = $pool
->getClient()
->getSyndicationService()
->pullSingle($flow->id, $entity_type_name, $bundle_name, $shared_entity_id)
->fromPool($pool->id)
->manually(true)
->execute()
->getPullDashboardSearchResultItem();
break 2;
} catch (SyncCoreException $e) {
return new ResourceResponse([
'message' => 'Failed to pull entity: ' . $e
->getMessage(),
], self::CODE_UNEXPECTED_ERROR);
}
}
}
if (!$preview_item) {
return new ResourceResponse([
'message' => "Missing flow for pool {$pool_id}.",
], self::CODE_NOT_FOUND);
}
$data = array_merge($preview_item
->toArray(), $this
->getPreviewItemData($preview_item
->getType(), $preview_item
->getBundle(), $preview_item
->getId()));
// Entity was ignored by the Sync Core for some reason or the update was rejected by Drupal.
if (empty($data['last_import'])) {
return new ResourceResponse([
'message' => 'Failed to pull entity. Pull was triggered but there\'s no new status entity.',
], self::CODE_UNEXPECTED_ERROR);
}
return new ResourceResponse($data);
}
/**
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*
* @return array
*/
protected function getPreviewItemData(string $entity_type_name, string $bundle_name, string $shared_entity_id) {
$data = [];
$data['entity_type_name'] = $entity_type_name;
$data['bundle_name'] = $bundle_name;
$data['entity_status'] = [];
$data['last_import'] = null;
$data['last_export'] = null;
$data['deleted'] = false;
$data['is_source'] = false;
/**
* @var \Drupal\Core\Entity\EntityInterface $entity
*/
if (EntityHandlerPluginManager::isEntityTypeConfiguration($entity_type_name)) {
$entity = \Drupal::entityTypeManager()
->getStorage($entity_type_name)
->load($shared_entity_id);
$entity_uuid = null;
}
else {
$entity = \Drupal::service('entity.repository')
->loadEntityByUuid($entity_type_name, $shared_entity_id);
$entity_uuid = $shared_entity_id;
}
if ($entity) {
if ($entity
->hasLinkTemplate('canonical')) {
try {
$url = $entity
->toUrl('canonical', [
'absolute' => true,
])
->toString(true)
->getGeneratedUrl();
$data['local_url'] = $url;
} catch (\Exception $e) {
}
}
$entity_uuid = $entity
->uuid();
}
if (!$entity_uuid) {
return $data;
}
$entity_status = EntityStatus::getInfosForEntity($entity_type_name, $entity_uuid);
foreach ($entity_status as $info) {
$data['entity_status'][] = [
'flow_id' => $info
->get('flow')->value,
'pool_id' => $info
->get('pool')->value,
'last_import' => $info
->getLastPull(),
'last_export' => $info
->getLastPush(),
];
if (!$data['last_import'] || $data['last_import'] < $info
->getLastPull()) {
$data['last_import'] = $info
->getLastPull();
}
if (!$data['last_export'] || $data['last_export'] < $info
->getLastPush()) {
$data['last_export'] = $info
->getLastPush();
}
if ($info
->isDeleted()) {
$data['deleted'] = true;
}
if ($info
->isSourceEntity()) {
$data['is_source'] = true;
}
}
// We had a bug before where the "deleted" flag wasn't set correctly locally. So we're mitigating for that here.
if ($data['last_import'] && !$entity) {
$data['deleted'] = true;
}
return $data;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PullEntity:: |
protected | property | ||
PullEntity:: |
protected | property | ||
PullEntity:: |
protected | property | ||
PullEntity:: |
protected | property | ||
PullEntity:: |
public | constant | ||
PullEntity:: |
public | constant | ||
PullEntity:: |
public | constant | ||
PullEntity:: |
public static | function |
Creates an instance of the plugin. Overrides ResourceBase:: |
|
PullEntity:: |
public | function | Responds to entity GET requests. | |
PullEntity:: |
protected | function | ||
PullEntity:: |
public | function | Responds to entity POST requests. | |
PullEntity:: |
public | function |
Constructs an object. Overrides ResourceBase:: |
|
ResourceBase:: |
protected | property | A logger instance. | |
ResourceBase:: |
protected | property | The available serialization formats. | |
ResourceBase:: |
public | function |
Returns the available HTTP request methods on this plugin. Overrides ResourceInterface:: |
1 |
ResourceBase:: |
protected | function | Gets the base route for a particular method. | 2 |
ResourceBase:: |
protected | function | Gets the base route requirements for a particular method. | 1 |
ResourceBase:: |
public | function |
Implements ResourceInterface::permissions(). Overrides ResourceInterface:: |
2 |
ResourceBase:: |
protected | function | Provides predefined HTTP request methods. | |
ResourceBase:: |
public | function |
Returns a collection of routes with URL path information for the resource. Overrides ResourceInterface:: |
|
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |