foldershare-8.x-1.2/src/Plugin/FolderShareCommand/Copy.php

src/Plugin/FolderShareCommand/Copy.php
<?php

namespace Drupal\foldershare\Plugin\FolderShareCommand;

use Symfony\Component\HttpFoundation\Request;

use Drupal\foldershare\Constants;
use Drupal\foldershare\Settings;
use Drupal\foldershare\Utilities\FormatUtilities;
use Drupal\foldershare\FolderShareInterface;
use Drupal\foldershare\Entity\FolderShare;
use Drupal\foldershare\Entity\Exception\RuntimeExceptionWithMarkup;
use Drupal\foldershare\Entity\Exception\ValidationException;

/**
 * Defines a command plugin to copy files and folders.
 *
 * The command copies all selected files and folders to a chosen
 * destination folder or the root list.
 *
 * Configuration parameters:
 * - 'parentId': the parent folder, if any.
 * - 'selectionIds': selected entities to duplicate.
 * - 'destinationId': the destination folder, if any.
 *
 * @ingroup foldershare
 *
 * @FolderShareCommand(
 *  id              = "foldersharecommand_copy",
 *  label           = @Translation("Copy"),
 *  menuNameDefault = @Translation("Copy..."),
 *  menuName        = @Translation("Copy..."),
 *  description     = @Translation("Copy selected files and folders to a new location."),
 *  category        = "copy & move",
 *  weight          = 10,
 *  userConstraints = {
 *    "authorpermission",
 *  },
 *  parentConstraints = {
 *    "kinds"   = {
 *      "rootlist",
 *      "folder",
 *    },
 *    "access"  = "view",
 *  },
 *  destinationConstraints = {
 *    "kinds"   = {
 *      "rootlist",
 *      "folder",
 *    },
 *    "access"  = "create",
 *  },
 *  selectionConstraints = {
 *    "types"   = {
 *      "one",
 *      "many",
 *    },
 *    "kinds"   = {
 *      "any",
 *    },
 *    "access"  = "view",
 *  },
 * )
 */
class Copy extends CopyMoveBase {

  /*--------------------------------------------------------------------
   *
   * Configuration.
   *
   *--------------------------------------------------------------------*/

  /**
   * {@inheritdoc}
   */
  public function validateDestinationConstraints() {
    if ($this->destinationValidated === TRUE) {
      return;
    }

    if ($this->selectionValidated === FALSE) {
      $this->validateSelectionConstraints();
    }

    // Handle special cases for destination.
    $destinationId = $this->getDestinationId();
    if ($destinationId === FolderShareInterface::ALL_ROOT_LIST) {
      $routeProvider = \Drupal::service('router.route_provider');
      $titleResolver = \Drupal::service('title_resolver');
      $dummyRequest = new Request();

      $route = $routeProvider->getRouteByName(
        Constants::ROUTE_ROOT_ITEMS_ALL);
      $title = $titleResolver->getTitle($dummyRequest, $route);

      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          'Items cannot be copied to the administrator\'s "@title" list.',
          [
            '@title' => $title,
          ]),
        t('Please select a subfolder instead.')));
    }

    if ($destinationId === FolderShareInterface::PUBLIC_ROOT_LIST) {
      $routeProvider = \Drupal::service('router.route_provider');
      $titleResolver = \Drupal::service('title_resolver');
      $dummyRequest = new Request();

      $route = $routeProvider->getRouteByName(
        Constants::ROUTE_ROOT_ITEMS_PUBLIC);
      $title = $titleResolver->getTitle($dummyRequest, $route);

      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          'Items cannot be copied to the "@title" list.',
          [
            '@title' => $title,
          ]),
        t('Please select a subfolder instead.')));
    }

    parent::validateDestinationConstraints();
  }

  /**
   * {@inheritdoc}
   */
  public function validateParameters() {
    if ($this->parametersValidated === TRUE) {
      // Already validated.
      return;
    }

    //
    // Validate destination.
    // ---------------------
    // There must be a destination ID. It must be a valid ID. It must
    // not be one of the selected items. And it must not be a descendant
    // of the selected items.
    //
    // A positive destination ID is for a folder to receive the selected
    // items.
    //
    // A negative destination ID is for the user's root list.
    $destinationId = $this->getDestinationId();

    if ($destinationId < 0) {
      // Destination is the user's root list. Nothing further to validate.
      $this->parametersValidated = TRUE;
      return;
    }

    // Destination is a specific folder.
    $destination = FolderShare::load($destinationId);

    if ($destination === NULL) {
      // Destination ID is not valid. This should have been caught
      // well before this validation stage.
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          '@method was called with an invalid entity ID "@id".',
          [
            '@method' => __METHOD__,
            '@id'     => $destinationId,
          ])));
    }

    // Verify that the destination is not in the selection. That would
    // be a copy to self, which is not valid.
    $selectionIds = $this->getSelectionIds();
    if (in_array($destinationId, $selectionIds) === TRUE) {
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t('Items cannot be copied into themselves.')));
    }

    // Verify that the destination is not a descendant of the selection.
    // That would be a recursive tree copy into itself.
    foreach ($selectionIds as $id) {
      $item = FolderShare::load($id);
      if ($item === NULL) {
        // The item does not exist.
        continue;
      }

      if ($destination->isDescendantOfFolderId($item->id()) === TRUE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t('Items cannot be copied into their own subfolders.')));
      }

      unset($item);
    }

    unset($destination);

    $this->parametersValidated = TRUE;

    // Garbage collect.
    gc_collect_cycles();
  }

  /*--------------------------------------------------------------------
   *
   * Configuration form.
   *
   *--------------------------------------------------------------------*/

  /**
   * {@inheritdoc}
   */
  public function getDescription(bool $forPage) {
    // The description varies for page vs. dialog:
    //
    // - Dialog: The description is longer and has the form "Copy OPERAND
    //   to a new location, including all of its contents?" For a single item,
    //   OPERAND is the NAME of the file/folder.
    //
    // - Page: The description is as for a dialog, except that the single
    //   item form is not included because it is already in the title.
    $selectionIds = $this->getSelectionIds();

    if (count($selectionIds) === 1) {
      // There is only one item. Load it.
      $item = FolderShare::load(reset($selectionIds));

      if ($forPage === TRUE) {
        // Page description. The page title already gives the name of the
        // item to be deleted. Don't include the item's name again here.
        if ($item->isFolder() === FALSE) {
          return [
            t(
              'Copy this @operand to a new location.',
              [
                '@operand' => FolderShare::translateKind($item->getKind()),
              ]),
          ];
        }

        return [
          t('Copy this folder to a new location, including all of its contents.'),
        ];
      }

      // Dialog description. Include the name of the item to be deleted.
      if ($item->isFolder() === FALSE) {
        return [
          t(
            'Copy "@name" to a new location.',
            [
              '@name' => $item->getName(),
            ]),
        ];
      }

      return [
        t(
          'Copy "@name" to a new location, including all of its contents.',
          [
            '@name' => $item->getName(),
          ]),
      ];
    }

    // Find the kinds for each of the selection IDs. Then choose an
    // operand based on the selection's single kind, or "items".
    $selectionKinds = FolderShare::findKindsForIds($selectionIds);
    if (count($selectionKinds) === 1) {
      $operand = FolderShare::translateKinds(key($selectionKinds));
    }
    else {
      $operand = FolderShare::translateKinds('items');
    }

    // Dialog and page description.
    //
    // Use the count and kind and end in a question mark. For folders,
    // include a reminder that all their contents are deleted too.
    if (isset($selectionKinds[FolderShare::FOLDER_KIND]) === FALSE) {
      return [
        t(
          'Copy these @operand to a new location.',
          [
            '@operand' => $operand,
          ]),
      ];
    }

    return [
      t(
        'Copy these @operand to a new location, including all of their contents?',
        [
          '@operand' => $operand,
        ]),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getTitle(bool $forPage) {
    // The title varies for page vs. dialog:
    //
    // - Dialog: "Copy".
    //
    // - Page: The title is longer and has the form "Copy OPERAND", where
    //   OPERAND can be the name of the item if one item is being deleted,
    //   or the count and kinds if multiple items are being deleted. This
    //   follows Drupal convention.
    if ($forPage === FALSE) {
      return t('Copy');
    }

    $selectionIds = $this->getSelectionIds();

    if (count($selectionIds) === 1) {
      // Page title. There is only one item. Load it.
      $item = FolderShare::load($selectionIds[0]);
      return t(
        'Copy "@name"',
        [
          '@name' => $item->getName(),
        ]);
    }

    // Find the kinds for each of the selection IDs. Then choose an
    // operand based on the selection's single kind, or "items".
    $selectionKinds = FolderShare::findKindsForIds($selectionIds);
    if (count($selectionIds) === 1) {
      $kind = key($selectionKinds);
      $operand = FolderShare::translateKind($kind);
    }
    elseif (count($selectionKinds) === 1) {
      $kind = key($selectionKinds);
      $operand = FolderShare::translateKinds($kind);
    }
    else {
      $operand = FolderShare::translateKinds('items');
    }

    // Include the count and operand kind.
    return t(
      "Copy @count @operand?",
      [
        '@count' => count($selectionIds),
        '@operand' => $operand,
      ]);
  }

  /**
   * {@inheritdoc}
   */
  public function getSubmitButtonName() {
    return t('Copy');
  }

  /*--------------------------------------------------------------------
   *
   * Execute.
   *
   *--------------------------------------------------------------------*/

  /**
   * {@inheritdoc}
   */
  public function execute() {
    $ids = $this->getSelectionIds();
    $destination = $this->getDestination();

    try {
      if ($destination === NULL) {
        FolderShare::copyToRootMultiple($ids);
      }
      else {
        FolderShare::copyToFolderMultiple($ids, $destination);
      }
    }
    catch (RuntimeExceptionWithMarkup $e) {
      \Drupal::messenger()->addMessage($e->getMarkup(), 'error', TRUE);
    }
    catch (\Exception $e) {
      \Drupal::messenger()->addMessage($e->getMessage(), 'error');
    }

    if (Settings::getCommandNormalCompletionReportEnable() === TRUE) {
      \Drupal::messenger()->addMessage(
        \Drupal::translation()->formatPlural(
          count($ids),
          "The item has been copied.",
          "@count items have been copied."),
        'status');
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc