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

src/Plugin/FolderShareCommand/FolderShareCommandBase.php
<?php
 
namespace Drupal\foldershare\Plugin\FolderShareCommand;
 
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\user\Entity\User;
 
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
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\ValidationException;
use Drupal\foldershare\Entity\FolderShareAccessControlHandler;
 
/**
 * Defines the base class for plugins for shared folder commands.
 *
 * A command performs an operation within the context of a parent folder
 * or list of folders, and operates upon a selection of FolderShare objects.
 * Typical operations are to create, delete, edit, rename, copy, move,
 * share, or change the ownership of items.
 *
 * A command implementation always includes three parts:
 *
 * - Validation that checks if a given configuration of parameters is
 *   consistent and valid for the command.
 *
 * - Access checks that confirm the user has permission to do the command.
 *
 * - Execution that performs the command.
 *
 * All commands use a configuration containing named parameters used as
 * operands for the command. These parameters may include the ID of the
 * parent folder, the IDs of operand files and folders, and so forth.
 *
 * Some commands may provide an optional form where a user may enter
 * additional parameters. A "folder rename" command, for instance, may
 * offer a form for entering a new name. When used, the form is expected
 * to create a configuration that is then passed to validation and
 * execution methods to do the operation.
 *
 * Callers may skip the command form and use their own mechanism to prompt
 * for configuration parameters. They may then call the command's validation
 * and execution methods directly to do the operation.
 *
 * For example, here are several situations that might all use the same
 * command:
 *
 * - Direct use. Code may instantiate a command plugin, set the configuration,
 *   then call the plugin's validation, and execution methods directly
 *   to perform an operation. No command form or UI would be used.
 *
 * - Custom UI. Code that creates its own user interface, with or without
 *   Javascript, may prompt the user for parameters, the invoke the command
 *   as above for direct use. The command's own forms would not be used.
 *
 * - Form page UI. Drupal's convention of full-page forms may be used to
 *   host a plugin command's forms plus a mechanism to choose a parent
 *   folder context and select files and folders to operate upon (these
 *   are not normally part of a command's own forms). On a submit, the
 *   command maps the form's values to its configuration, then validates,
 *   and executes.
 *
 * - Embedded form UI. When an overlay/dialog can be used, the plugin
 *   command's forms may be embedded within the overlay. Any mechanism to
 *   select the parent folder context and select files and folders must be
 *   done before this overlay. On a submit of the overlay form, the
 *   command maps the form's values to its configuration, then validates
 *   and executes.
 *
 * @ingroup foldershare
 */
abstract class FolderShareCommandBase extends PluginBase implements ConfigurableInterface, FolderShareCommandInterface {
 
  /*--------------------------------------------------------------------
   *
   * Fields.
   *
   * These fields provide state set during different stages of command
   * handling. The parent, destination, and selection are set as the
   * command is validatedfor a specific configuration, which is held
   * in the parent class. The validation flags are set during stages
   * of validation so that repeated calls to validate don't repeat
   * the associated work.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * The loaded parent folder, if any.
   *
   * @var \Drupal\foldershare\FolderShareInterface
   */
  private $parent;
 
  /**
   * The loaded destination folder, if any.
   *
   * @var \Drupal\foldershare\FolderShareInterface
   */
  private $destination;
 
  /**
   * The loaded selection, if any.
   *
   * The selection is an associative array where keys are kinds, and
   * values are arrays of FolderShare entities.
   *
   * @var \Drupal\foldershare\FolderShareInterface[]
   */
  private $selection;
 
  /**
   * A flag indicating if command is allowed on the site.
   *
   * @var bool
   */
  protected $commandAllowed;
 
  /**
   * A flag indicating if user constraints have been validated.
   *
   * @var bool
   */
  protected $userValidated;
 
  /**
   * A flag indicating if parent constraints have been validated.
   *
   * @var bool
   */
  protected $parentValidated;
 
  /**
   * A flag indicating if selection constraints have been validated.
   *
   * @var bool
   */
  protected $selectionValidated;
 
  /**
   * A flag indicating if destination constraints have been validated.
   *
   * @var bool
   */
  protected $destinationValidated;
 
  /**
   * A flag indicating if additional parameters have been validated.
   *
   * @var bool
   */
  protected $parametersValidated;
 
  /*--------------------------------------------------------------------
   *
   * Construct.
   *
   * These functions create an instance of a command. Every instance
   * has a definition that describes the command, and a configuration
   * that provides operands for the command. The definition never
   * changes, but the configuration may change as the command is
   * prepared for execution. Validation focuses on the configuration,
   * while the plugin manager has already insured that the command
   * definition is proper.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Constructs a new plugin with the given configuration.
   *
   * @param array $configuration
   *   The array of named parameters for the new command instance.
   * @param string $pluginId
   *   The ID for the new plugin instance.
   * @param mixed $pluginDefinition
   *   The plugin's implementation definition.
   */
  public function __construct(
    array $configuration,
    $pluginId,
    $pluginDefinition) {
 
    parent::__construct($configuration, $pluginId, $pluginDefinition);
 
    // Set the configuration, which adds in defaults and clears
    // cached values.
    $this->setConfiguration($configuration);
  }
 
  /*--------------------------------------------------------------------
   *
   * Configuration.
   * (Implements ConfigurableInterface)
   *
   * These functions handle the command's configuration, which is an
   * associative array of named operands for the command. All commands
   * support several well-known operands:
   *
   * - parentId: The entity ID of the parent item, such as a folder.
   *
   * - destinationId: The entity ID of the destination item, such as a folder.
   *
   * - selectionIds: An array of entity IDs of selected items, such as
   *   files and folders.
   *
   * For parentId and destinationId, two special negative values are supported:
   * - FolderShareInterface::USER_ROOT_LIST indicates the user's root list.
   * - self::EMPTY_ITEM_ID indicates no ID has been provided (yet?).
   *
   * For selectionIds, the array may be empty, but the individual values must
   * all be valid positive entity IDs.
   *
   * When a command is created, an initial configuration is set by the
   * caller, combined with a default configuration. Thereafter the caller
   * may change the configuration. On any change, internal state is reset
   * to insure that the new configuration gets validated and used in
   * further calls to the command.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Returns a required default configuration.
   *
   * The related function, defaultConfiguration(), is intended to provide
   * a default initial configuration for the command. Subclasses may
   * override this to change the default. Unfortunately, they also may
   * override this and fail to provide a default.
   *
   * To insure that there is always a valid starting default configuration,
   * this function returns the required minimal default configuration.
   *
   * @return array
   *   Returns an associative array with keys and values set for a
   *   required minimal configuration.
   *
   * @see defaultConfiguration()
   */
  private function requiredDefaultConfiguration() {
    //
    // The required minimal default configuration has the well-known
    // common configuration keys and initial values for:
    // - no parent.
    // - no destination.
    // - no selection.
    return [
      'parentId'      => self::EMPTY_ITEM_ID,
      'destinationId' => self::EMPTY_ITEM_ID,
      'selectionIds'  => [],
      'uploadClass'   => '',
    ];
  }
 
  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    //
    // Return a default fully-initialized configuration used during
    // construction of the command, or to reset it for repeated use.
    //
    // Subclasses may override this function to add further configuration
    // defaults.
    return $this->requiredDefaultConfiguration();
  }
 
  /**
   * {@inheritdoc}
   */
  public function getConfiguration() {
    //
    // Return the current configuration, which is an associative array
    // with well-known and subclass-specific keys for command operands.
    return $this->configuration;
  }
 
  /**
   * {@inheritdoc}
   */
  public function setConfiguration(array $configuration) {
    //
    // Set the configuration.
    //
    // To insure that the configuration always has minimal default settings,
    // the given configuration is merged with the command's defaults and
    // a minimal required set of defaults.
    $this->configuration = ($configuration + $this->defaultConfiguration());
    $this->configuration += $this->requiredDefaultConfiguration();
 
    // Clear cached values for the parent (if any), destination (if any),
    // and selection (if any).
    $this->parent      = NULL;
    $this->destination = NULL;
    $this->selection   = [];
 
    // Clear validation flags. The new configuration is not validated until
    // the validation functions are called explicitly, or until the
    // configuration is used.
    $this->validated            = FALSE;
    $this->commandAllowed       = FALSE;
    $this->parentValidated      = FALSE;
    $this->selectionValidated   = FALSE;
    $this->destinationValidated = FALSE;
    $this->parametersValidated  = FALSE;
 
    // If the configuration has a list of selected entity IDs, clean the
    // list by converting all values to integers and tossing anything
    // invalid. This makes later use of the list easier.
    $ids = $this->configuration['selectionIds'];
    if (empty($ids) === FALSE) {
      foreach ($ids as $index => $id) {
        $iid = (int) $id;
        if ($iid >= 0) {
          $ids[$index] = $iid;
        }
      }
    }
    else {
      $ids = [];
    }
 
    $this->configuration['selectionIds'] = $ids;
 
    // If the configuration has parent or destination IDs, make sure
    // they are integers.
    if (empty($this->configuration['parentId']) === FALSE) {
      $this->configuration['parentId'] = (int) $this->configuration['parentId'];
    }
 
    if (empty($this->configuration['destinationId']) === FALSE) {
      $this->configuration['destinationId'] = (int) $this->configuration['destinationId'];
    }
  }
 
  /*--------------------------------------------------------------------
   *
   * Configuration shortcuts - Misc.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Returns true if the command uses file uploads.
   *
   * @return bool
   *   Returns TRUE if the command's special handling includes 'upload'.
   */
  public function doesFileUploads() {
    $def = $this->getPluginDefinition();
    return (in_array('upload', $def['specialHandling']));
  }
 
  /*--------------------------------------------------------------------
   *
   * Configuration shortcuts - Parent.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Gets and loads the configuration's parent folder, if any.
   *
   * If the parent folder has not been loaded yet, it is loaded and
   * cached.
   *
   * If there is no parent folder specified, or if a root list is specified,
   * then a NULL is returned.
   *
   * @return \Drupal\foldershare\FolderShareInterface
   *   Returns the parent folder, or NULL if there is no parent or the parent
   *   is a root list.
   *
   * @see ::getParentId()
   */
  protected function getParent() {
    // If there is a loaded parent, return it.
    if ($this->parent !== NULL) {
      return $this->parent;
    }
 
    // If there is no parent or the parent is the root list, return NULL.
    $parentId = $this->getParentId();
    if ($parentId < 0) {
      return NULL;
    }
 
    // Load the parent and cache the result.
    $this->parent = FolderShare::load($parentId);
    return $this->parent;
  }
 
  /**
   * Gets the configuration's parent folder ID, if any.
   *
   * @return int
   *   Returns the positive integer folder ID of the parent folder.
   *   The negative self::EMPTY_ITEM_ID indicates that no parent has been set.
   *   The negative FolderShareInterface::USER_ROOT_LIST indicates the
   *   user's root list.
   *
   * @see ::getParent()
   */
  protected function getParentId() {
    if (empty($this->configuration['parentId']) === TRUE) {
      return self::EMPTY_ITEM_ID;
    }
 
    return (int) $this->configuration['parentId'];
  }
 
  /**
   * Returns TRUE if the configuration's parent folder ID has been set.
   *
   * @return bool
   *   Returns TRUE if the configuration's parent ID field has been set
   *   and is not EMPTY_ITEM_ID.
   */
  protected function isParentIdSet() {
    return ($this->getParentId() !== self::EMPTY_ITEM_ID);
  }
 
  /**
   * Sets the configuration's parent folder ID.
   *
   * @param int $id
   *   The positive integer folder ID of the destination folder. Setting
   *   the value to self::EMPTY_ITEM_ID marks the field as empty. Setting
   *   the value to FolderShareInterface::USER_ROOT_LIST indicates the
   *   user's root list.
   */
  protected function setParentId(int $id) {
    $this->configuration['parentId'] = $id;
    $this->parent = NULL;
  }
 
  /*--------------------------------------------------------------------
   *
   * Configuration shortcuts - Destination.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Gets and loads the configuration's destination folder, if any.
   *
   * If the destination folder has not been loaded yet, it is loaded
   * and cached.
   *
   * If there is no destination folder specified, or if a root list is
   * specified, then a NULL is returned.
   *
   * @return \Drupal\foldershare\FolderShareInterface
   *   Returns the destination folder, or NULL if there is no destination
   *   or the destination is a root list.
   *
   * @see ::getDestinationId()
   */
  protected function getDestination() {
    // If there is a loaded destination, return it.
    if ($this->destination !== NULL) {
      return $this->destination;
    }
 
    // If there is no destination in the configuration, return NULL.
    $destinationId = $this->getDestinationId();
    if ($destinationId < 0) {
      return NULL;
    }
 
    // Load the destination and cache the result.
    $this->destination = FolderShare::load($destinationId);
    return $this->destination;
  }
 
  /**
   * Gets the configuration's destination folder ID, if any.
   *
   * @return int
   *   Returns the positive integer folder ID of the destination folder.
   *   The negative self::EMPTY_ITEM_ID indicates that no destination has
   *   been set. The negative FolderShareInterface::USER_ROOT_LIST indicates
   *   the user's root list.
   *
   * @see ::getDestination()
   */
  protected function getDestinationId() {
    if (empty($this->configuration['destinationId']) === TRUE) {
      return self::EMPTY_ITEM_ID;
    }
 
    return (int) $this->configuration['destinationId'];
  }
 
  /**
   * Returns TRUE if the configuration's destination folder ID has been set.
   *
   * @return bool
   *   Returns TRUE if the configuration's destination ID field has been set
   *   and is not EMPTY_ITEM_ID.
   */
  protected function isDestinationIdSet() {
    return ($this->getDestinationId() !== self::EMPTY_ITEM_ID);
  }
 
  /**
   * Sets the configuration's destination folder ID.
   *
   * @param int $id
   *   The positive integer folder ID of the destination folder. Setting
   *   the value to self::EMPTY_ITEM_ID marks the field as empty. Setting
   *   the value to FolderShareInterface::USER_ROOT_LIST indicates the
   *   user's root list.
   */
  protected function setDestinationId(int $id) {
    $this->configuration['destinationId'] = $id;
    $this->destination = NULL;
  }
 
  /*--------------------------------------------------------------------
   *
   * Configuration shortcuts - Selection.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Gets and loads the configuration's array of selected items, if any.
   *
   * If the selected items have not been loaded yet, they are loaded
   * and cached. If there are no selected items, an empty array is returned.
   * If any file cannot be loaded, a NULL is included in the array.
   *
   * The returned associative array has FolderShare kind names as keys,
   * and values that are arrays of loaded FolderShare objects.
   *
   * @return \Drupal\foldershare\FolderShareInterface[]
   *   Returns an array of selected items, or an empty array if there
   *   are no selected items.
   */
  protected function getSelection() {
    // If there are loaded selected items, return them.
    if (empty($this->selection) === FALSE) {
      return $this->selection;
    }
 
    // If there is no selection in the configuration, return an empty array.
    $ids = $this->getSelectionIds();
    if (empty($ids) === TRUE) {
      return [];
    }
 
    // Load the items, sort them by kind, and cache the result.
    $items = FolderShare::loadMultiple($ids);
    $sel = [];
    foreach ($items as $item) {
      if ($item === NULL) {
        continue;
      }
 
      $kind = $item->getKind();
      if (isset($sel[$kind]) === FALSE) {
        $sel[$kind] = [$item];
      }
      else {
        $sel[$kind][] = $item;
      }
    }
 
    $this->selection = $sel;
    return $this->selection;
  }
 
  /**
   * Gets the configuration's array of selected entity IDs.
   *
   * @return int[]
   *   Returns an array of positive integer entity IDs for selected items,
   *   or an empty array if there are no selected items. The returned IDs
   *   cannot be negative.
   */
  protected function getSelectionIds() {
    $ids = $this->configuration['selectionIds'];
    if (empty($ids) === TRUE) {
      return [];
    }
 
    return $ids;
  }
 
  /*--------------------------------------------------------------------
   *
   * Validate.
   *
   * Validation may be partial or complete. Partial validation means there
   * are errors or something is missing. Complete validation means the
   * configuration is ready for use in executing a command.
   *
   * To keep track of partial validation, the configuration can be validated
   * in stages, in this order:
   * - Validate command use.
   * - Validate parent.
   * - Validate selection.
   * - Validate destination.
   * - Validate additional parameters.
   *
   * Command use validation checks if the site allows the command at all.
   *
   * Parent validation insures the parent folder ID in the configuration
   * meets the command's criteria (see command annotation).
   *
   * Selection validation insures the selection IDs in the configuration
   * meets the command's criteria (see command annotation).
   *
   * Destination validation insures the destination folder ID in the
   * configuration meets the command's criteria (see command annotation).
   *
   * Additional parameter validation lets the command validate any special
   * arguments it may need. These are usually collected from forms.
   *
   * Each validation stage sets flags upon completion so that the
   * validation doesn't have to be repeated if nothing changes in the
   * configuration.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * {@inheritdoc}
   */
  public function isValidated() {
    return $this->commandAllowed === TRUE &&
      $this->userValidated === TRUE &&
      $this->parentValidated === TRUE &&
      $this->selectionValidated === TRUE &&
      $this->destinationValidated === TRUE &&
      $this->parametersValidated === TRUE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateConfiguration() {
    // Validate command is enabled by site.
    $this->validateCommandAllowed();
 
    // Validate the user constraints.
    $this->validateUserConstraints();
 
    // Validate the parent constraints.
    $this->validateParentConstraints();
 
    // Validate the selection constraints.
    $this->validateSelectionConstraints();
 
    // Validate the destination constraints.
    $this->validateDestinationConstraints();
 
    // Validate any other parameters for the command.
    $this->validateParameters();
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateCommandAllowed() {
    if ($this->commandAllowed === TRUE) {
      return;
    }
 
    // Check site settings to insure the command is allowed.
    if (Settings::getCommandMenuRestrict() === TRUE) {
      $commandId = $this->getPluginDefinition()['id'];
      $allowedIds = Settings::getCommandMenuAllowed();
      if (in_array($commandId, $allowedIds) === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'The @command operation is not available.',
            [
              '@command' => $this->getPluginDefinition()['label'],
            ]),
          t('The site administrator has disabled this activity.')));
      }
    }
 
    // Validated!
    $this->commandAllowed = TRUE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateUserConstraints() {
    if ($this->userValidated === TRUE) {
      return;
    }
 
    if ($this->commandAllowed === FALSE) {
      $this->validateCommandAllowed();
    }
 
    //
    // Setup.
    // ------
    // Get the command's definition and its constraints.
    $def = $this->getPluginDefinition();
    $userConstraints = $def['userConstraints'];
    $user = \Drupal::currentUser();
 
    //
    // Check user constraints.
    // -----------------------
    // If the "any" constraint is present, no checking is needed. Otherwise,
    // check each of the well-known user constraints.
    if (in_array('any', $userConstraints) === FALSE) {
      $allowed = FALSE;
      if (in_array('authenticated', $userConstraints) === TRUE &&
          $user->isAuthenticated() === TRUE) {
        $allowed = TRUE;
      }
      elseif (in_array('anonymous', $userConstraints) === TRUE &&
          $user->isAnonymous() === TRUE) {
        $allowed = TRUE;
      }
      elseif (in_array('adminpermission', $userConstraints) === TRUE &&
          $user->hasPermission(Constants::ADMINISTER_PERMISSION) === TRUE) {
        $allowed = TRUE;
      }
      elseif (in_array('noadminpermission', $userConstraints) === TRUE &&
          $user->hasPermission(Constants::ADMINISTER_PERMISSION) === FALSE) {
        $allowed = TRUE;
      }
      elseif (in_array('viewpermission', $userConstraints) === TRUE &&
          $user->hasPermission(Constants::VIEW_PERMISSION) === TRUE) {
        $allowed = TRUE;
      }
      elseif (in_array('authorpermission', $userConstraints) === TRUE &&
          $user->hasPermission(Constants::AUTHOR_PERMISSION) === TRUE) {
        $allowed = TRUE;
      }
      elseif (in_array('sharepermission', $userConstraints) === TRUE &&
          $user->hasPermission(Constants::SHARE_PERMISSION) === TRUE) {
        $allowed = TRUE;
      }
      elseif (in_array('sharepublicpermission', $userConstraints) === TRUE &&
          $user->hasPermission(Constants::SHARE_PUBLIC_PERMISSION) === TRUE) {
        $allowed = TRUE;
      }
 
      if ($allowed === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t('You do not have permission to complete this operation.'),
          t('This command is restricted to specific types of users.')));
      }
    }
 
    // Validated!
    $this->userValidated = TRUE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateParentConstraints() {
    if ($this->parentValidated === TRUE) {
      return;
    }
 
    if ($this->userValidated === FALSE) {
      $this->validateUserConstraints();
    }
 
    //
    // Setup.
    // ------
    // Get the command's definition and its constraints.
    $def = $this->getPluginDefinition();
    $label = $def['label'];
 
    // Get the parent's kind.
    //
    // At this stage, the parent ID can be one of:
    // - FolderShareInterface::USER_ROOT_LIST.
    // - FolderShareInterface::PUBLIC_ROOT_LIST.
    // - FolderShareInterface::ALL_ROOT_LIST.
    // - A valid entity ID.
    $parentId = $this->getParentId();
    $parent = NULL;
 
    if ($parentId < 0) {
      // Simplify special entity IDs.
      switch ($parentId) {
        default:
        case FolderShareInterface::ALL_ROOT_LIST:
          // While an admin can operate on anybody's root items in the "all"
          // list, if they create anything (new folder, duplicate, upload,
          // compress, uncompress, etc.), it goes into their own root list.
          // So, treat the "all" list as the user's root list.
          $parentId = FolderShareInterface::USER_ROOT_LIST;
          $this->setParentId($parentId);
          break;
 
        case FolderShareInterface::USER_ROOT_LIST:
        case FolderShareInterface::PUBLIC_ROOT_LIST:
          // Continue to distinguish between the user and public lists.
          break;
 
        case self::EMPTY_ITEM_ID:
          // This should not happen. It means the UI did not fill in the
          // parent ID.
          throw new ValidationException(FormatUtilities::createFormattedMessage(
            t(
              'Missing parent folder ID for the "@command" command.',
              [
                '@command' => $label,
              ]),
            t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
 
      $parentKind = 'rootlist';
    }
    else {
      $parent = $this->getParent();
      if ($parent === NULL) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Missing parent folder ID for the "@command" command.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
 
      if ($parent->isSystemHidden() === TRUE) {
        // Hidden items do not exist.
        throw new NotFoundHttpException(
          FolderShare::getStandardHiddenMessage($parent->getName()));
      }
 
      if ($parent->isSystemDisabled() === TRUE) {
        // Disabled items cannot be used.
        throw new ConflictHttpException(
          FolderShare::getStandardDisabledMessage(
            'accessed',
            $parent->getName()));
      }
 
      $parentKind = $parent->getKind();
    }
 
    //
    // Check parent kind.
    // ------------------
    // Compare the parent kind against the list of supported kinds
    // for the command.
    $allowedKinds = $def['parentConstraints']['kinds'];
 
    if (in_array('any', $allowedKinds) === FALSE) {
      if ($parentKind === 'rootlist' &&
          in_array('rootlist', $allowedKinds) === FALSE) {
        // Parent is a root list but the command doesn't support that.
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Root list provided instead of a required parent folder ID for the "@command" command.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
      elseif (in_array($parentKind, $allowedKinds) === FALSE) {
        // Parent provided but its kind is not supported by the command.
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Parent item provided does not meet the "@command" command\'s requirements.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
    }
 
    //
    // Check parent ownership.
    // -----------------------
    // Confirm that the parent meets ownership constraints.
    // Skip the check if the command supports 'any' as an ownership choice
    // (which is the default).
    $allowedOwnership = $def['parentConstraints']['ownership'];
    $user             = \Drupal::currentUser();
 
    if (in_array('any', $allowedOwnership) === FALSE) {
      $userId    = (int) $user->id();
      $anonymous = User::getAnonymousUser();
      $anonId    = (int) $anonymous->id();
      $allowed   = FALSE;
 
      if ($parent !== NULL) {
        // There is a parent entity. Check it against the allowed
        // ownership constraints.
        //
        // Since access grants are set on the root only, use it to determine
        // the sharing status below.
        $root = $parent->getRootItem();
 
        if (in_array('ownedbyuser', $allowedOwnership) === TRUE &&
            $parent->isOwnedBy($userId) === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('ownedbyanonymous', $allowedOwnership) === TRUE &&
            $parent->isOwnedBy($anonId) === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('ownedbyanother', $allowedOwnership) === TRUE &&
            $parent->isOwnedBy($userId) === FALSE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedbyuser', $allowedOwnership) === TRUE &&
            $root->isSharedBy($userId) === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithusertoview', $allowedOwnership) === TRUE &&
            $root->isSharedWith($userId, 'view') === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithusertoauthor', $allowedOwnership) === TRUE &&
            $root->isSharedWith($userId, 'author') === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithanonymoustoview', $allowedOwnership) === TRUE &&
            $root->isSharedWith($anonId, 'view') === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithanonymoustoauthor', $allowedOwnership) === TRUE &&
            $root->isSharedWith($anonId, 'author') === TRUE) {
          $allowed = TRUE;
        }
      }
      else {
        // There is no parent entity. The parent is a rootlist. For purposes
        // of parent ownership checking:
        // - USER_ROOT_LIST is owned by the current user.
        // - PUBLIC_ROOT_LIST is owned by anonymous.
        if ($parentId === FolderShareInterface::USER_ROOT_LIST) {
          if (in_array('ownedbyuser', $allowedOwnership) === TRUE) {
            $allowed = TRUE;
          }
        }
        elseif ($parentId === FolderShareInterface::PUBLIC_ROOT_LIST) {
          if (in_array('ownedbyanonymous', $allowedOwnership) === TRUE) {
            $allowed = TRUE;
          }
          elseif (in_array('sharedwithanonymoustoview', $allowedOwnership) === TRUE &&
              $anonymous->hasPermission(Constants::VIEW_PERMISSION) === TRUE) {
            $allowed = TRUE;
          }
          elseif (in_array('sharedwithanonymoustoauthor', $allowedOwnership) === TRUE &&
              $anonymous->hasPermission(Constants::AUTHOR_PERMISSION) === TRUE) {
            $allowed = TRUE;
          }
        }
      }
 
      if ($allowed === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Parent item provided does not meet the "@command" command\'s ownership requirements.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
    }
 
    //
    // Check parent access.
    // --------------------
    // Check if the required access is allowed for the parent or root list.
    // Handle 'create' specially since it is not available via access().
    $allowedAccess = $def['parentConstraints']['access'];
    if ($parent !== NULL) {
      $allowed = $parent->access($allowedAccess, $user, FALSE);
    }
    else {
      $summary = FolderShareAccessControlHandler::getRootAccessSummary($parentId, $user);
      if (isset($summary[$allowedAccess]) === TRUE &&
          $summary[$allowedAccess] === TRUE) {
        $allowed = TRUE;
      }
      else {
        $allowed = FALSE;
      }
    }
 
    if ($allowed === FALSE) {
      if ($parentId >= 0) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t('You do not have permission to complete this operation.'),
          t('The current folder is restricted and cannot be accessed.')));
      }
 
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t('You do not have permission to complete this operation.'),
        t('The current top-level list is restricted and cannot be accessed.')));
    }
 
    // Validated!
    $this->parentValidated = TRUE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateSelectionConstraints() {
    if ($this->selectionValidated === TRUE) {
      return;
    }
 
    if ($this->parentValidated === FALSE) {
      $this->validateParentConstraints();
    }
 
    $def          = $this->getPluginDefinition();
    $label        = $def['label'];
    $allowedTypes = $def['selectionConstraints']['types'];
 
    if (in_array('none', $allowedTypes) === TRUE) {
      // No selection required!
      //
      // Validated!
      $this->selectionValidated = TRUE;
      return;
    }
 
    //
    // Setup.
    // ------
    // Get the parent ID. Parent validation has already simplified the
    // range of values to:
    // - FolderShareInterface::USER_ROOT_LIST.
    // - FolderShareInterface::PUBLIC_ROOT_LIST.
    // - A valid entity ID.
    $parentId = $this->getParentId();
 
    // Count the total number of selected items.
    $selectionIds      = $this->getSelectionIds();
    $nSelected         = count($selectionIds);
    $selectionIsParent = FALSE;
 
    //
    // Check selection size.
    // ---------------------
    // Insure the selection size is compatible with the command.
    //
    // Config selection   Command constraints   Result
    // ----------------   -------------------   ------
    // none, one, many    none needed           allowed.
    // none               can have parent       allowed, use parent.
    // none               cannot have parent    fail, need selection.
    // one                can have one          allowed, use selection.
    // one                cannot have one       fail, need more.
    // many               can have many         allowed, use selection.
    // many               cannot have many      fail, need fewer.
    $canHaveOne    = in_array('one', $allowedTypes);
    $canHaveMany   = in_array('many', $allowedTypes);
    $canHaveParent = in_array('parent', $allowedTypes);
 
    $allowed = TRUE;
    $failureIsMultiple = TRUE;
 
    if ($nSelected === 0) {
      if ($canHaveParent === TRUE && $parentId >= 0) {
        // There is no selection, the command can default to the parent,
        // and there is a parent!
        $nSelected = 1;
        $selectionIsParent = TRUE;
      }
      else {
        // There is no selection, but either the command cannot default to
        // the parent, or there is no parent. Fail.
        $allowed = FALSE;
        $failureIsMultiple = ($canHaveMany === TRUE);
      }
    }
    elseif ($nSelected > 1 && $canHaveMany === FALSE) {
      // There are multiple items selected, but the command does not allow
      // that. Fail.
      $allowed = FALSE;
      $failureIsMultiple = FALSE;
    }
    elseif ($nSelected === 1 && $canHaveOne === FALSE && $canHaveMany === FALSE) {
      // There is just one item selected, but the command does not allow
      // having just one or even lots of items selected. Fail.
      $allowed = FALSE;
      $failureIsMultiple = TRUE;
    }
 
    if ($allowed === FALSE) {
      if ($failureIsMultiple === TRUE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Multiple selection IDs required for the "@command" command.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
 
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          'Single selection ID required for the "@command" command.',
          [
            '@command' => $label,
          ]),
        t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
    }
 
    if ($selectionIsParent === FALSE) {
      $selection = $this->getSelection();
    }
    else {
      $parent = $this->getParent();
      $selection[$parent->getKind()] = [$parent];
    }
 
    //
    // Check selection kinds.
    // ----------------------
    // Insure the kinds of items in the selection are compatible with
    // the command.
    //
    // Config selection   Command constraints   Result
    // ----------------   -------------------   ------
    // any                any                   allowed, use selection.
    // specific kind      kind                  allowed, if they match.
    $allowedKinds = $def['selectionConstraints']['kinds'];
 
    if (in_array('any', $allowedKinds) === FALSE) {
      $allowed = TRUE;
      foreach (array_keys($selection) as $kind) {
        if (in_array($kind, $allowedKinds) === FALSE) {
          $allowed = FALSE;
          break;
        }
      }
 
      if ($allowed === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Selection provided does not meet the "@command" command\'s kind requirements.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
    }
 
    //
    // Check selection validity and parentage.
    // ---------------------------------------
    // Confirm that all of the selected items are children of the parent,
    // if any. Skip this check if the selection has been defaulted to
    // the parent.
    //
    // Config parent    Item's parent   Result
    // -------------    -------------   ------
    // USER_ROOT_LIST   USER_ROOT_LIST  Allowed.
    // USER_ROOT_LIST   integer         Fail, item should have no parent.
    // PUBLIC_ROOT_LIST USER_ROOT_LIST  Allowed.
    // PUBLIC_ROOT_LIST integer         Fail, item should have no parent.
    // integer          USER_ROOT_LIST  Fail, item should have a parent.
    // integer          integer         Allowed if they match.
    if ($selectionIsParent === FALSE) {
      foreach ($selection as $kind => $items) {
        foreach ($items as $item) {
          if ($item === NULL || $item->isSystemHidden() === TRUE) {
            // Bad items or hidden items do not exist.
            throw new NotFoundHttpException(
              FolderShare::getStandardHiddenMessage($item->getName()));
          }
 
          if ($item->isSystemDisabled() === TRUE) {
            // Disabled items cannot be used.
            throw new ConflictHttpException(
              FolderShare::getStandardDisabledMessage(
                'accessed',
                $item->getName()));
          }
 
          if ($parentId === FolderShareInterface::USER_ROOT_LIST ||
              $parentId === FolderShareInterface::PUBLIC_ROOT_LIST) {
            // The configuration's parent is the user or public root list.
            // If the item is a root item, then allowed.
            $allowed = ($item->isRootItem() === TRUE);
          }
          else {
            // The configuration's parent is a non-root item. If the item
            // is not a root, then allowed.
            $allowed = ($item->isRootItem() === FALSE);
          }
 
          if ($allowed === FALSE) {
            throw new ValidationException(FormatUtilities::createFormattedMessage(
              t(
                'Selection provided does not meet the "@command" command\'s parentage requirements.',
                [
                  '@command' => $label,
                ]),
              t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
          }
        }
      }
    }
 
    //
    // Check selection ownership.
    // --------------------------
    // Confirm that all of the selected items meet ownership constraints.
    // Skip the check if the command supports 'any' as an ownership choice
    // (which is the default).
    $allowedOwnership = $def['selectionConstraints']['ownership'];
    $user = \Drupal::currentUser();
 
    if (in_array('any', $allowedOwnership) === FALSE) {
      $userId    = (int) $user->id();
      $anonymous = User::getAnonymousUser();
      $anonId    = (int) $anonymous->id();
 
      $checkOwnedByAnonymous = in_array('ownedbyanonymous', $allowedOwnership);
      $checkOwnedByAnother   = in_array('ownedbyanother', $allowedOwnership);
      $checkOwnedByUser      = in_array('ownedbyuser', $allowedOwnership);
 
      $checkSharedByUser =
        in_array('sharedbyuser', $allowedOwnership);
      $checkSharedWithAnonymousToView =
        in_array('sharedwithanonymoustoview', $allowedOwnership);
      $checkSharedWithAnonymousToAuthor =
        in_array('sharedwithanonymoustoauthor', $allowedOwnership);
      $checkSharedWithUserToView =
        in_array('sharedwithusertoview', $allowedOwnership);
      $checkSharedWithUserToAuthor =
        in_array('sharedwithusertoauthor', $allowedOwnership);
 
      // Since access grants are set on the root only, use it to determine
      // the sharing status below. Get the root below from the first selected
      // item. All items in the selection list have already been validated to
      // have the same parent, so they'll have the same root too.
      $root = NULL;
      $allowed = TRUE;
      foreach ($selection as $kind => $items) {
        foreach ($items as $item) {
          $itemIsAllowed = FALSE;
 
          // For the first item in the selection, get the root. It will be
          // the same root for everything in the selection.
          if ($root === NULL) {
            $root = $item->getRootItem();
          }
 
          if ($checkOwnedByUser === TRUE &&
              $item->isOwnedBy($userId) === TRUE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkOwnedByAnonymous === TRUE &&
              $item->isOwnedBy($anonId) === TRUE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkOwnedByAnother === TRUE &&
              $item->isOwnedBy($userId) === FALSE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkSharedByUser === TRUE &&
              $root->isSharedBy($userId) === TRUE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkSharedWithUserToView === TRUE &&
              $root->isSharedWith($userId, 'view') === TRUE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkSharedWithUserToAuthor === TRUE &&
              $root->isSharedWith($userId, 'author') === TRUE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkSharedWithAnonymousToView === TRUE &&
              $root->isSharedWith($anonId, 'view') === TRUE) {
            $itemIsAllowed = TRUE;
          }
          elseif ($checkSharedWithAnonymousToAuthor === TRUE &&
              $root->isSharedWith($anonId, 'author') === TRUE) {
            $itemIsAllowed = TRUE;
          }
 
          if ($itemIsAllowed === FALSE) {
            $allowed = FALSE;
            break 2;
          }
        }
      }
 
      if ($allowed === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Selection provided does not meet the "@command" command\'s ownership requirements.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
    }
 
    //
    // Check selection file extensions.
    // --------------------------------
    // Confirm that all of the selected items meet file name extension
    // constraints.  Skip the check if the command has no extensions
    // (which is the default).
    $allowedExtensions = $def['selectionConstraints']['fileExtensions'];
 
    if (empty($allowedExtensions) === FALSE) {
      $allowed = TRUE;
      foreach ($selection as $kind => $items) {
        foreach ($items as $item) {
          $ext = $item->getExtension();
          if (empty($ext) === TRUE) {
            $allowed = FALSE;
            break 2;
          }
 
          if (in_array($ext, $allowedExtensions) === FALSE) {
            $allowed = FALSE;
            break 2;
          }
        }
      }
 
      if ($allowed === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Selection provided does not meet the "@command" command\'s file name extension requirements.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
    }
 
    //
    // Check selection access.
    // -----------------------
    // If there is a selection and access is required, check for access.
    // Commands that do not require a selection, or selection access, have
    // an access operation of 'none'.
    $allowedAccess = $def['selectionConstraints']['access'];
    $allowed == TRUE;
    foreach ($selection as $items) {
      foreach ($items as $item) {
        if ($item->access($allowedAccess, $user, FALSE) === FALSE) {
          $allowed = FALSE;
          break 2;
        }
      }
    }
 
    if ($allowed === FALSE) {
      if ($selectionIsParent === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t('You do not have permission to complete this operation.'),
          t('One or more selected items are restricted and cannot be accessed.')));
      }
 
      if ($parentId >= 0) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t('You do not have permission to complete this operation.'),
          t('The current folder is restricted and cannot be accessed.')));
      }
 
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t('You do not have permission to complete this operation.'),
        t('The current top-level list is restricted and cannot be accessed.')));
    }
 
    // Validated!
    $this->selectionValidated = TRUE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateDestinationConstraints() {
    if ($this->destinationValidated === TRUE) {
      return;
    }
 
    if ($this->selectionValidated === FALSE) {
      $this->validateSelectionConstraints();
    }
 
    $def          = $this->getPluginDefinition();
    $label        = $def['label'];
    $allowedKinds = $def['destinationConstraints']['kinds'];
 
    if (in_array('none', $allowedKinds) === TRUE) {
      // No destination required.
      //
      // Validated!
      $this->destinationValidated = TRUE;
      return;
    }
 
    //
    // Setup.
    // ------
    // Get the destinations's kind.
    $destinationId = $this->getDestinationId();
    $destination = NULL;
    if ($destinationId === self::EMPTY_ITEM_ID) {
      $destinationKind = 'none';
    }
    elseif ($destinationId === FolderShareInterface::USER_ROOT_LIST) {
      $destinationKind = 'rootlist';
    }
    else {
      $destination = $this->getDestination();
      if ($destination === NULL) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Missing destination folder ID for the "@command" command.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
 
      if ($destination->isSystemHidden() === TRUE) {
        // Hidden items do not exist.
        throw new NotFoundHttpException(
          FolderShare::getStandardHiddenMessage($destination->getName()));
      }
 
      if ($destination->isSystemDisabled() === TRUE) {
        // Disabled items cannot be used.
        throw new ConflictHttpException(
          FolderShare::getStandardDisabledMessage(
            'accessed',
            $destination->getName()));
      }
 
      $destinationKind = $destination->getKind();
    }
 
    //
    // Check destination kind.
    // -----------------------
    // Compare the destination kind against the list of supported kinds
    // for the command.
    if ($destinationKind === 'none' &&
        in_array('none', $allowedKinds) === FALSE) {
      // There is no destination but the command doesn't support that.
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          'Missing required destination folder ID for the "@command" command.',
          [
            '@command' => $label,
          ]),
        t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
    }
    elseif ($destinationKind === 'rootlist' &&
        in_array('rootlist', $allowedKinds) === FALSE) {
      // Destination is a root list but the command doesn't support that.
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          'Root list provided instead of a required destination folder ID for the "@command" command.',
          [
            '@command' => $label,
          ]),
        t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
    }
    elseif (in_array($destinationKind, $allowedKinds) === FALSE &&
        in_array('any', $allowedKinds) === FALSE) {
      // Destination provided but its kind is not supported by the command.
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t(
          'Destination item provided does not meet the "@command" command\'s requirements.',
          [
            '@command' => $label,
          ]),
        t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
    }
 
    //
    // Check destination ownership.
    // ----------------------------
    // Confirm that the destination meets ownership constraints.
    // Skip the check if the command supports 'any' as an ownership choice
    // (which is the default).
    //
    // Rootlists are not owned, so there is no ownership constraint for them.
    $allowedOwnership = $def['destinationConstraints']['ownership'];
    $user = \Drupal::currentUser();
 
    if (in_array('any', $allowedOwnership) === FALSE) {
      $userId    = (int) $user->id();
      $anonymous = User::getAnonymousUser();
      $anonId    = (int) $anonymous->id();
 
      if ($destination !== NULL) {
        // There is a destination entity. Check it against the allowed
        // ownership constraints.
        //
        // Since access grants are set on the root only, use it to determine
        // the sharing status below.
        $root = $destination->getRootItem();
 
        $allowed = FALSE;
        if (in_array('ownedbyuser', $allowedOwnership) === TRUE &&
            $destination->isOwnedBy($userId) === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('ownedbyanonymous', $allowedOwnership) === TRUE &&
            $destination->isOwnedBy($anonId) === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('ownedbyanother', $allowedOwnership) === TRUE &&
            $destination->isOwnedBy($userId) === FALSE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedbyuser', $allowedOwnership) === TRUE &&
            $root->isSharedBy($userId) === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithusertoview', $allowedOwnership) === TRUE &&
            $root->isSharedWith($userId, 'view') === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithusertoauthor', $allowedOwnership) === TRUE &&
            $root->isSharedWith($userId, 'author') === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithanonymoustoview', $allowedOwnership) === TRUE &&
            $root->isSharedWith($anonId, 'view') === TRUE) {
          $allowed = TRUE;
        }
        elseif (in_array('sharedwithanonymoustoauthor', $allowedOwnership) === TRUE &&
            $root->isSharedWith($anonId, 'author') === TRUE) {
          $allowed = TRUE;
        }
      }
      else {
        // There is no destination entity. The destination is a rootlist.
        // For purposes of destination ownership checking:
        // - USER_ROOT_LIST is owned by the current user.
        // - PUBLIC_ROOT_LIST is owned by anonymous.
        if ($destinationId === FolderShareInterface::USER_ROOT_LIST) {
          if (in_array('ownedbyuser', $allowedOwnership) === TRUE) {
            $allowed = TRUE;
          }
        }
        elseif ($destinationId === FolderShareInterface::PUBLIC_ROOT_LIST) {
          if (in_array('ownedbyanonymous', $allowedOwnership) === TRUE) {
            $allowed = TRUE;
          }
          elseif (in_array('sharedwithanonymoustoview', $allowedOwnership) === TRUE &&
              $anonymous->hasPermission(Constants::VIEW_PERMISSION) === TRUE) {
            $allowed = TRUE;
          }
          elseif (in_array('sharedwithanonymoustoauthor', $allowedOwnership) === TRUE &&
              $anonymous->hasPermission(Constants::AUTHOR_PERMISSION) === TRUE) {
            $allowed = TRUE;
          }
        }
      }
 
      if ($allowed === FALSE) {
        throw new ValidationException(FormatUtilities::createFormattedMessage(
          t(
            'Destination item provided does not meet the "@command" command\'s ownership requirements.',
            [
              '@command' => $label,
            ]),
          t('This is probably due to a programming error in the user interface. Please report this to the developers.')));
      }
    }
 
    //
    // Check destination access
    // ------------------------
    // If there is a destination and access is required, check for access.
    // Commands that do not require a destination, or destination access, have
    // an access operation of 'none'.
    $allowedAccess = $def['destinationConstraints']['access'];
    if ($destination !== NULL) {
      $allowed = $destination->access($allowedAccess, $user, FALSE);
    }
    else {
      $summary = FolderShareAccessControlHandler::getRootAccessSummary($destinationId, $user);
      if (isset($summary[$allowedAccess]) === TRUE &&
          $summary[$allowedAccess] === TRUE) {
        $allowed = TRUE;
      }
      else {
        $allowed = FALSE;
      }
    }
 
    if ($allowed === FALSE) {
      throw new ValidationException(FormatUtilities::createFormattedMessage(
        t('You do not have permission to complete this operation.'),
        t('The destination folder is restricted and cannot be accessed.')));
    }
 
    // Validated!
    $this->destinationValidated = TRUE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateParameters() {
    if ($this->parametersValidated === TRUE) {
      return;
    }
 
    if ($this->destinationValidated === FALSE) {
      $this->validateDestinationConstraints();
    }
 
    // Validated!
    $this->parametersValidated = TRUE;
  }
 
  /*--------------------------------------------------------------------
   *
   * Execute.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * {@inheritdoc}
   */
  abstract public function execute();
 
  /*---------------------------------------------------------------------
   *
   * Execution behavior.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * {@inheritdoc}
   */
  public function getExecuteBehavior() {
    return FolderShareCommandInterface::POST_EXECUTE_VIEW_REFRESH;
  }
 
  /**
   * {@inheritdoc}
   */
  public function getExecuteRedirectUrl() {
    return NULL;
  }
 
  /*---------------------------------------------------------------------
   *
   * Configuration forms.
   *
   *---------------------------------------------------------------------*/
 
  /**
   * {@inheritdoc}
   */
  public function getDescription(bool $forPage) {
    return [];
  }
 
  /**
   * {@inheritdoc}
   */
  public function getTitle(bool $forPage) {
    return $this->getPluginDefinition()['label'];
  }
 
  /**
   * {@inheritdoc}
   */
  public function getSubmitButtonName() {
    return t('OK');
  }
 
  /**
   * {@inheritdoc}
   */
  public function hasConfigurationForm() {
    return FALSE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(
    array $form,
    FormStateInterface $formState) {
    return $form;
  }
 
  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(
    array &$form,
    FormStateInterface $formState) {
  }
 
  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(
    array &$form,
    FormStateInterface $formState) {
  }
 
  /*--------------------------------------------------------------------
   *
   * Debug.
   *
   *--------------------------------------------------------------------*/
 
  /**
   * Returns a string representation of the plugin.
   *
   * @return string
   *   A string representation of the plugin.
   */
  public function __toString() {
    $def = $this->getPluginDefinition();
    $s = 'FolderShareCommand: ' . $def['id'] . "\n";
 
    $s .= '  parent ID: "' . $this->getParentId() . "\"\n";
    $s .= '  destination ID: "' . $this->getDestinationId() . "\"\n";
    $s .= '  selection IDs: ';
    $ids = $this->getSelectionIds();
    if (empty($ids) === TRUE) {
      $s .= '(empty)';
    }
    else {
      foreach ($ids as $id) {
        $s .= ' "' . $id . '"';
      }
    }
 
    $s .= "\n";
 
    $s .= '  configuration keys: ';
    foreach (array_keys($this->configuration) as $key) {
      $s .= ' "' . $key . '"';
    }
 
    $s .= "\n";
 
    return $s;
  }
 
}

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

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