Newer
Older
<?php
/**
* @file
* Contains entity_clone.module.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity_clone\EntityClone\Config\ConfigEntityCloneBase;
use Drupal\entity_clone\EntityClone\Config\ConfigEntityCloneFormBase;
use Drupal\entity_clone\EntityClone\Config\ConfigWithFieldEntityClone;
use Drupal\entity_clone\EntityClone\Config\FieldConfigEntityClone;
use Drupal\entity_clone\EntityClone\Config\MenuEntityClone;
use Drupal\entity_clone\EntityClone\Config\MenuEntityCloneForm;
use Drupal\entity_clone\EntityClone\Content\ContentEntityCloneBase;
use Drupal\entity_clone\EntityClone\Content\ContentEntityCloneFormBase;
use Drupal\entity_clone\EntityClone\Content\FileEntityClone;
use Drupal\entity_clone\EntityClone\Content\TaxonomyTermEntityClone;
use Drupal\entity_clone\EntityClone\Content\UserEntityClone;
use Drupal\entity_clone\EntityClone\Config\LayoutBuilderEntityClone;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* Implements hook_help().
*/
function entity_clone_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the entity_clone module.
case 'help.page.entity_clone':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Provides a new operation to clone all Entities.') . '</p>';
return $output;
default:
return;
}
}
/**
* Implements hook_entity_type_build().
*/
function entity_clone_entity_type_build(array &$entity_types) {
$specific_handler = [
'file' => [
'entity_clone' => FileEntityClone::class,
],
'user' => [
'entity_clone' => UserEntityClone::class,
],
'field_config' => [
'entity_clone' => FieldConfigEntityClone::class,
],
'node_type' => [
'entity_clone' => ConfigWithFieldEntityClone::class,
],
'comment_type' => [
'entity_clone' => ConfigWithFieldEntityClone::class,
],
'block_content_type' => [
'entity_clone' => ConfigWithFieldEntityClone::class,
],
'contact_form' => [
'entity_clone' => ConfigWithFieldEntityClone::class,
],
'taxonomy_term' => [
'entity_clone' => TaxonomyTermEntityClone::class,
],
'menu' => [
'entity_clone_form' => MenuEntityCloneForm::class,
'entity_clone' => MenuEntityClone::class,
],
'taxonomy_vocabulary' => [
'entity_clone' => ConfigWithFieldEntityClone::class,
],
'entity_view_display' => [
'entity_clone' => \Drupal::moduleHandler()->moduleExists('layout_builder') ? LayoutBuilderEntityClone::class : NULL,
],
];
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
foreach ($entity_types as $entity_type_id => $entity_type) {
$has_entity_clone_handler = $entity_type->getHandlerClass('entity_clone');
if (!$has_entity_clone_handler) {
if ($entity_type instanceof ContentEntityTypeInterface) {
$entity_type->setHandlerClass('entity_clone', ContentEntityCloneBase::class);
$entity_type->setHandlerClass('entity_clone_form', ContentEntityCloneFormBase::class);
}
elseif ($entity_type instanceof ConfigEntityTypeInterface) {
$entity_type->setHandlerClass('entity_clone', ConfigEntityCloneBase::class);
$entity_type->setHandlerClass('entity_clone_form', ConfigEntityCloneFormBase::class);
if (isset($specific_handler[$entity_type->id()]['entity_clone'])) {
$entity_type->setHandlerClass('entity_clone', $specific_handler[$entity_type->id()]['entity_clone']);
if (isset($specific_handler[$entity_type->id()]['entity_clone_form'])) {
$entity_type->setHandlerClass('entity_clone_form', $specific_handler[$entity_type->id()]['entity_clone_form']);
$entity_type->setLinkTemplate('clone-form', "/entity_clone/$entity_type_id/{{$entity_type_id}}");
}
}
/**
* Declares entity operations.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity on which the linked operations will be performed.
*
* @return array
* An operations array as returned by
* EntityListBuilderInterface::getOperations().
*
* @see \Drupal\Core\Entity\EntityListBuilderInterface::getOperations()
*/
function entity_clone_entity_operation(EntityInterface $entity) {
if ($entity->hasLinkTemplate('clone-form') && $entity->access('clone') && !$entity->isNew()) {
return [
'clone' => [
'title' => t('Clone'),
'weight' => 50,
'url' => $entity->toUrl('clone-form')
->mergeOptions(['query' => \Drupal::destination()->getAsArray()]),
],
];
}
return [];
}
/**
* Implements hook_entity_access().
function entity_clone_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
if ($operation !== 'clone') {
return AccessResult::neutral();
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
$cache = new CacheableMetadata();
$cache->addCacheContexts(['user.permissions']);
// Deny access if the user cannot clone the entity.
$access = AccessResult::forbiddenIf(!$account->hasPermission('clone ' . $entity->getEntityTypeId() . ' entity'));
if ($access->isForbidden()) {
return $access->addCacheableDependency($cache);
}
// Deny access if the user can clone but cannot create new entities of this
// type. However, we have some exceptions in which the access control handler
// doesn't have a say in things. In these cases, we go based on the clone
// permission only.
$exceptions = [
'file',
'paragraph',
];
if (in_array($entity->getEntityTypeId(), $exceptions)) {
return AccessResult::allowed()->addCacheableDependency($cache);
}
$handler = \Drupal::entityTypeManager()->getAccessControlHandler($entity->getEntityTypeId());
$access = $handler->createAccess($entity->bundle(), $account, [], TRUE);
if (!$access->isAllowed()) {
$cache->addCacheableDependency($access);
$forbidden = AccessResult::forbidden();
return $forbidden->addCacheableDependency($cache);
}
return AccessResult::allowed()->addCacheableDependency($cache);