Same filename in other branches
  1. 2.x entity_clone.module

Contains entity_clone.module.

File

./entity_clone.module

View source
<?php


/**
 * @file
 * Contains entity_clone.module.
 */
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
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\LayoutBuilderEntityClone;
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;

/**
 * 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();
    }
    $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);
}

Functions

Title Deprecated Summary
entity_clone_entity_access Implements hook_entity_access().
entity_clone_entity_operation Declares entity operations.
entity_clone_entity_type_build Implements hook_entity_type_build().
entity_clone_help Implements hook_help().