contacts-8.x-1.x-dev/src/Plugin/Block/ContactsEntity.php

src/Plugin/Block/ContactsEntity.php
<?php

namespace Drupal\contacts\Plugin\Block;

use Drupal\contacts\Plugin\DashboardBlockInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Form\FormBuilder;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\user\Entity\Role;
use Drupal\user\EntityOwnerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a block the user entity and any entity implementing ownership.
 *
 * Entity classes need to implement the EntityOwnerInterface and define the
 * contacts_entity property in their definition.
 *
 * @Block(
 *   id = "contacts_entity",
 *   category = @Translation("Dashboard Blocks"),
 *   deriver = "Drupal\contacts\Plugin\Deriver\ContactsEntityBlockDeriver",
 * )
 */
class ContactsEntity extends BlockBase implements ContainerFactoryPluginInterface, DashboardBlockInterface {

  const MODE_VIEW = 'view';
  const MODE_VIEW_NEW = 'view_new';
  const MODE_FORM = 'form';

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The entity form builder.
   *
   * @var \Drupal\Core\Entity\EntityFormBuilderInterface
   */
  protected $formBuilder;

  /**
   * The current request.
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $request;

  /**
   * The entity display repository.
   *
   * @var \Drupal\Core\Entity\EntityDisplayRepository
   */
  protected $entityDisplayRepository;

  /**
   * The current user service.
   *
   * @var \Drupal\Core\Session\AccountProxy
   */
  protected $currentUser;

  /**
   * The class resolver.
   *
   * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
   */
  protected $classResolver;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;


  /**
   * The tab manager.
   *
   * @var \Drupal\contacts\ContactsTabManager
   */
  protected $contactsTabManager;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $plugin = new static($configuration, $plugin_id, $plugin_definition);
    $plugin->entityTypeManager = $container->get('entity_type.manager');
    $plugin->formBuilder = $container->get('entity.form_builder');
    $plugin->request = $container->get('request_stack')->getCurrentRequest();
    $plugin->entityDisplayRepository = $container->get('entity_display.repository');
    $plugin->currentUser = $container->get('current_user');
    $plugin->classResolver = $container->get('class_resolver');
    $plugin->moduleHandler = $container->get('module_handler');
    $plugin->contactsTabManager = $container->get('contacts.tab_manager');
    return $plugin;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'mode' => self::MODE_VIEW,
      'create' => NULL,
      'operation' => 'contacts_dashboard',
      'view_mode' => 'contacts_dashboard',
      'edit_link' => $this->pluginDefinition['_has_forms'] ? self::EDIT_LINK_CONTENT : FALSE,
      'edit_id' => 'edit',
      'view_new_text' => '',
      'custom_access' => NULL,
    ] + parent::defaultConfiguration();
  }

  /**
   * {@inheritdoc}
   */
  protected function blockAccess(AccountInterface $account) {
    // Get our entity from the context.
    $entity = $this->getContextValue('entity');
    if (!$entity) {
      $entity = $this->createEntity();
      if (!$entity) {
        return AccessResult::forbidden();
      }
    }

    // Get our mode.
    $op = $this->getMode($entity);

    // Allow custom access callbacks.
    if ($this->configuration['custom_access']) {
      $callable = $this->configuration['custom_access'];

      // Handle class/service methods.
      if (strpos($callable, '::') !== FALSE) {
        $callable = explode('::', $callable, 2);
        $callable[0] = $this->classResolver->getInstanceFromDefinition($callable[0]);
      }

      // If it's callable, do so.
      if (is_callable($callable)) {
        return call_user_func($callable, $this, $entity, $op, $account);
      }
      // Otherwise forbid access.
      else {
        return AccessResult::forbidden('Invalid custom access callback.');
      }
    }

    // Default to entity access controls.
    return $entity->access($op, $account, TRUE);
  }

  /**
   * Whether we should use edit links.
   *
   * @return bool
   *   Whether we should use edit links.
   */
  protected function useEditLink() {
    return $this->pluginDefinition['_has_forms'] && $this->configuration['edit_link'] && !empty($this->configuration['edit_id']);
  }

  /**
   * {@inheritdoc}
   */
  public function getEditLink($mode) {
    // Check that we support and want edit links.
    if (!$this->useEditLink()) {
      return FALSE;
    }

    // Check we should show an edit link in this place.
    if ($this->configuration['edit_link'] != $mode) {
      return FALSE;
    }

    // If we are already in edit mode, don't show a link.
    if ($this->request->query->has('edit')) {
      return FALSE;
    }

    // If we are already in edit mode, don't show a link.
    if ($this->getMode() == 'update') {
      return FALSE;
    }

    if (empty($this->getContextValue('user')) || empty($this->getContextValue('subpage'))) {
      return FALSE;
    }

    $params = [
      'user' => $this->getContextValue('user')->id(),
      'subpage' => $this->getContextValue('subpage'),
    ];

    $options = ['query' => ['edit' => $this->configuration['edit_id']]];
    $link = Link::createFromRoute('Edit',
      'contacts.contact',
      $params,
      $options);

    return $link;
  }

  /**
   * {@inheritdoc}
   */
  public function processManageMode(array &$variables) {
    $definition = $this->getPluginDefinition();

    $bundle = $definition['_bundle_key'] ? $definition['_bundle_id'] : $definition['_entity_type_id'];
    $variables['attributes']['data-contacts-manage-entity-type'] = $variables['entity'] = $definition['_entity_type_id'];
    $variables['attributes']['data-contacts-manage-entity-bundle'] = $variables['bundle'] = $bundle;

    $variables['content']['links'] = [
      '#theme' => 'item_list',
      '#list_type' => 'ul',
      '#items' => $this->getManageLinks(),
    ];

    if (!empty($definition['_required_hats'])) {
      $hats = [];
      // @todo Show hat icons instead of labels.
      foreach ($definition['_required_hats'] as $hat) {
        $hats[] = [
          '#theme' => 'crm_tools_hat',
          '#role' => $hat,
        ];
      }
      $variables['footer']['visible_hats'] = $hats;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    // @todo Can we set the default mode to MODE_VIEW_NEW?
    $form['mode'] = [
      '#type' => 'select',
      '#options' => [
        self::MODE_FORM => $this->t('Form'),
        self::MODE_VIEW => $this->t('View existing'),
        self::MODE_VIEW_NEW => $this->t('View always'),
      ],
      '#title' => $this->t('Show as'),
      '#default_value' => $this->configuration['mode'],
    ];

    // If entity has bundles get bundle specific display modes.
    if ($this->pluginDefinition['_bundle_key']) {
      $view_mode_options = $this->entityDisplayRepository->getViewModeOptionsByBundle($this->pluginDefinition['_entity_type_id'], $this->pluginDefinition['_bundle_id']);
      $form_mode_options = $this->entityDisplayRepository->getFormModeOptionsByBundle($this->pluginDefinition['_entity_type_id'], $this->pluginDefinition['_bundle_id']);
    }
    else {
      $view_mode_options = $this->entityDisplayRepository->getViewModeOptions($this->pluginDefinition['_entity_type_id']);
      $form_mode_options = $this->entityDisplayRepository->getFormModeOptions($this->pluginDefinition['_entity_type_id']);
    }

    // @todo figure out how we can get the parent form structure.
    $form['view_mode'] = [
      '#type' => 'select',
      '#options' => $view_mode_options,
      '#title' => $this->t('View mode'),
      '#default_value' => $this->configuration['view_mode'],
      '#states' => [
        'visible' => [
          ':input[name="settings[mode]"]' => [
            '!value' => self::MODE_FORM,
          ],
        ],
      ],
    ];

    $form['operation'] = [
      '#type' => 'select',
      '#options' => $form_mode_options,
      '#title' => $this->t('Form mode'),
      '#default_value' => $this->configuration['operation'],
    ];

    $entity_type = $this->entityTypeManager->getDefinition($this->pluginDefinition['_entity_type_id']);
    $form['view_new_text'] = [
      '#type' => 'textarea',
      '#title' => $this->t('No existing entity text'),
      '#desciption' => $this->t("Optional text to display if viewing and there isn't already a @entity_type.", [
        '@entity_type' => $entity_type->getSingularLabel(),
      ]),
      '#default_value' => $this->configuration['view_new_text'],
      '#states' => [
        'visible' => [
          ':input[name="settings[mode]"]' => [
            'value' => self::MODE_VIEW_NEW,
          ],
        ],
      ],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['mode'] = $form_state->getValue('mode');
    $this->configuration['view_mode'] = $form_state->getValue('view_mode');
    $this->configuration['operation'] = $form_state->getValue('operation');
    $this->configuration['view_new_text'] = $form_state->getValue('view_new_text');
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $this->getContextValue('entity');

    // If we don't have an entity, attempt creation.
    if (!$entity) {
      $entity = $this->createEntity();

      // If we still have no entity, return an empty render array.
      if (!$entity) {
        return [
          'no_entity' => [
            '#type' => 'html_tag',
            '#tag' => 'p',
            '#markup' => $this->configuration['view_new_text'],
          ],
        ];
      }
    }

    if ($this->getMode($entity) == 'update') {
      return $this->buildForm($entity);
    }
    return $this->buildView($entity);
  }

  /**
   * Get the mode to show for the entity.
   *
   * @param null|\Drupal\Core\Entity\EntityInterface $entity
   *   The entity. If not provided, we will get it from the context.
   *
   * @return string
   *   The mode to use, either 'view' or 'update'.
   */
  protected function getMode(?EntityInterface $entity = NULL) {
    $definition = $this->getPluginDefinition();
    $config = $this->getConfiguration();
    if (!$entity) {
      $entity = $this->getContextValue('entity');
    }

    // If there are no forms, always show a view.
    if (!$definition['_has_forms']) {
      return 'view';
    }

    // Show a form if we are form only.
    if ($config['mode'] == self::MODE_FORM) {
      return 'update';
    }

    // If we have requested this to be editable, show the form.
    if ($this->useEditLink() && $this->request->query->get('edit') == $this->configuration['edit_id']) {
      return 'update';
    }

    // View if the entity is not new or we want to view new entities.
    if (!$entity || !$entity->isNew() || $config['mode'] == self::MODE_VIEW_NEW) {
      return 'view';
    }

    return 'update';
  }

  /**
   * Create an entity, if the definition and config allow it.
   *
   * @return false|\Drupal\Core\Entity\EntityInterface
   *   The created entity or FALSE if the definition or config do not allow it.
   */
  protected function createEntity() {
    // Check our definition allows creation.
    $definition = $this->getPluginDefinition();
    if (!$definition['_allow_create']) {
      return FALSE;
    }

    // Check our config allows creation.
    $config = $this->getConfiguration();
    if (!$config['create']) {
      return FALSE;
    }

    // Check create access.
    $bundle = $definition['_bundle_key'] ? $definition['_bundle_id'] : NULL;
    $context = [];
    if (is_a($this->entityTypeManager->getDefinition($definition['_entity_type_id'])->getClass(), EntityOwnerInterface::class, TRUE)) {
      $user = $this->getContextValue('user');
      $context['owner'] = $user;
    }
    if (!$this->entityTypeManager->getAccessControlHandler($definition['_entity_type_id'])->createAccess($bundle, NULL, $context)) {
      return FALSE;
    }

    // Build our values.
    $values = [];

    // If this entity type has bundles, set the appropriate key.
    if ($bundle) {
      $values[$definition['_bundle_key']] = $bundle;
    }

    // Create the entity.
    $entity = $this->entityTypeManager->getStorage($definition['_entity_type_id'])->create($values);

    // If this has an owner, set it.
    if ($entity instanceof EntityOwnerInterface) {
      $entity->setOwner($this->getContextValue('user'));
    }

    return $entity;
  }

  /**
   * Build the view mode render array for the block.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   *
   * @return array
   *   A render array containing the rendered entity.
   */
  protected function buildView(EntityInterface $entity) {
    $build = [];

    if ($entity->isNew()) {
      $build['no_entity'] = [
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => $this->configuration['view_new_text'],
      ];
    }

    // Output an edit link if relevant.
    if ($link = $this->getEditLink(self::EDIT_LINK_CONTENT)) {
      $build['edit'] = $link->toRenderable();
    }
    elseif ($link = $this->getEditLink(self::EDIT_LINK_TITLE)) {
      $build['#title_edit'] = $link;
    }

    // Get the view builder.
    $definition = $this->getPluginDefinition();
    $config = $this->getConfiguration();
    $view_builder = $this->entityTypeManager->getViewBuilder($definition['_entity_type_id']);
    $build['view'] = $view_builder->view($entity, $config['view_mode']);

    return $build;
  }

  /**
   * Build the form mode render array for the block.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   *
   * @return array
   *   A render array containing the form.
   */
  protected function buildForm(EntityInterface $entity) {
    // Manually build our action and redirect.
    $route_name = 'contacts.contact';
    $route_params = [
      'user' => $this->getContextValue('user')->id(),
      'subpage' => $this->getContextValue('subpage'),
    ];

    $options = ['query' => $this->request->query->all()];
    // @see \Drupal\Core\Form\FormBuilder::buildFormAction.
    unset($options['query'][FormBuilder::AJAX_FORM_REQUEST], $options['query'][MainContentViewSubscriber::WRAPPER_FORMAT]);

    // Build our redirect URL.
    unset($options['query']['edit']);
    $redirect = Url::fromRoute($route_name, $route_params, $options);

    // Get the form.
    $config = $this->getConfiguration();

    // Fall back to the default form if the requested one doesn't exist.
    if ($this->entityTypeManager->getDefinition($this->pluginDefinition['_entity_type_id'], TRUE)->getFormClass($config['operation'])) {
      $operation = $config['operation'];
    }
    else {
      $operation = 'default';
    }

    $form = $this->formBuilder->getForm($entity, $operation, [
      'redirect' => $redirect,
    ]);

    return ['form' => $form];
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    $dependencies = parent::calculateDependencies();
    $definition = $this->getPluginDefinition();

    $entity_type = $this->entityTypeManager->getDefinition($this->pluginDefinition['_entity_type_id']);

    // Add the module which defines the entity type.
    $dependencies['module'][] = $entity_type->getProvider();

    // If we have a bundle for creating, add it's config dependencies.
    if ($definition['_bundle_key']) {
      $dependency = $entity_type->getBundleConfigDependency($definition['_bundle_id']);
      $dependencies[$dependency['type']][] = $dependency['name'];
    }

    return $dependencies;
  }

  /**
   * Get list of links to display on manage block.
   *
   * @return array
   *   Array of links to be based to an 'item_list' render array.
   */
  protected function getManageLinks() {
    $entity_id = $this->pluginDefinition['_entity_type_id'];
    $bundle_id = $this->pluginDefinition['_bundle_id'];
    $entity_definition = $this->entityTypeManager->getDefinition($entity_id);
    $bundle_type = $entity_definition->getBundleEntityType();
    $operations = [];
    // Add manage fields and display links if this entity type is the bundle
    // of another and that type has field UI enabled.
    if ($bundle_type) {
      $link_options = [
        'attributes' => ['target' => '_blank'],
      ];

      // @todo Solve generic entity access permission issue.
      $operations['manage-entity'] = [
        '#type' => 'link',
        '#title' => $this->t('Edit profile type'),
        '#weight' => 10,
        '#url' => Url::fromRoute("entity.{$bundle_type}.edit_form", [
          $bundle_type => $bundle_id,
        ], $link_options),
      ];

      if ($entity_definition->get('field_ui_base_route') && $this->moduleHandler->moduleExists('field_ui')) {
        if ($this->currentUser->hasPermission('administer ' . $entity_id . ' fields')) {
          $operations['manage-fields'] = [
            '#type' => 'link',
            '#title' => $this->t('Manage fields'),
            '#weight' => 15,
            '#url' => Url::fromRoute("entity.{$entity_id}.field_ui_fields", [
              $bundle_type => $bundle_id,
            ], $link_options),
          ];
        }
        if ($this->currentUser->hasPermission('administer ' . $entity_id . ' form display')) {
          $operations['manage-form-display'] = [
            '#type' => 'link',
            '#title' => $this->t('Manage form display'),
            '#weight' => 20,
            '#url' => Url::fromRoute("entity.entity_form_display.{$entity_id}.default", [
              $bundle_type => $bundle_id,
            ], $link_options),
          ];
        }
        if ($this->currentUser->hasPermission('administer ' . $entity_id . ' display')) {
          $operations['manage-display'] = [
            '#type' => 'link',
            '#title' => $this->t('Manage display'),
            '#weight' => 25,
            '#url' => Url::fromRoute("entity.entity_view_display.{$entity_id}.default", [
              $bundle_type => $bundle_id,
            ], $link_options),
          ];
        }
      }
    }

    return $operations;
  }

  /**
   * {@inheritdoc}
   */
  public function getManageMeta() {
    $meta = [
      '#type' => 'details',
      '#open' => TRUE,
      '#title' => 'About this block',
    ];

    $definition = $this->getPluginDefinition();
    $entity_type_definition = $this->entityTypeManager->getDefinition($definition['_entity_type_id']);
    $entity_bundle_type = $entity_type_definition->getBundleEntityType();
    if ($entity_bundle_type && $definition['_bundle_id']) {
      $bundle_entity = $this->entityTypeManager->getStorage($entity_bundle_type)->load($definition['_bundle_id']);
    }

    $hats = [];

    if (isset($bundle_entity)) {
      // Get user roles.
      $roles = Role::loadMultiple();
      uasort($roles, 'contacts_sort_roles');
      $roles = array_intersect(array_keys($roles), $bundle_entity->getRoles());
      // @todo Show hat icons instead of labels.
      foreach ($roles as $role) {
        $hats[] = [
          '#theme' => 'crm_tools_hat',
          '#role' => $role,
        ];
      }
    }

    $meta['needed_hats'] = [
      '#theme' => 'item_list',
      '#items' => $hats,
      '#title' => 'Allowed for users with hats:',
    ];

    $tabs = $this->contactsTabManager->getTabsWithBlock($this->getPluginId());
    $meta['placed_tabs'] = [
      '#theme' => 'item_list',
      '#items' => $tabs,
      '#title' => 'Currently placed on tabs:',
    ];

    $meta['manage_links'] = [
      '#theme' => 'item_list',
      '#items' => $this->getManageLinks(),
      '#title' => 'Manage:',
    ];

    return $meta;
  }

}

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

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