You are here

abstract class AbstractEntityFormModesFactory in Form mode manager 8.2

Abstract Factory to generate object used by routing of Form Mode Manager.

This Factory are responsible to generate objects specific for each entities, variations. In drupal we have few and unpredictable variants of entities, this factory make a very generic object to be used by controller to make, add/edit/add_page/add_admin Entity forms without duplicated code. The most common variant of entity are Entities with bundles and entities, without bundles (named unbundled in that module). Another case for Taxonomy, are a good example of why this Factory exists because that entity haven't, the common entityKey 'type' but use 'vid' instead, if that transverse, module need to work in every cases we need to assume that variant by other, way to use ton of code complexity.

Hierarchy

Expanded class hierarchy of AbstractEntityFormModesFactory

File

src/AbstractEntityFormModesFactory.php, line 30

Namespace

Drupal\form_mode_manager
View source
abstract class AbstractEntityFormModesFactory implements EntityFormModeManagerInterface {
  use StringTranslationTrait;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $account;

  /**
   * The entity display repository.
   *
   * @var \Drupal\form_mode_manager\FormModeManagerInterface
   */
  protected $formModeManager;

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

  /**
   * The Routes Manager Plugin.
   *
   * @var \Drupal\form_mode_manager\EntityRoutingMapManager
   */
  protected $entityRoutingMap;

  /**
   * The form builder.
   *
   * @var \Drupal\Core\Form\FormBuilderInterface
   */
  protected $formBuilder;

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

  /**
   * Constructs a EntityFormModeController object.
   *
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   * @param \Drupal\form_mode_manager\FormModeManagerInterface $form_mode_manager
   *   The form mode manager.
   * @param \Drupal\Core\Entity\EntityFormBuilderInterface $entity_form_builder
   *   The entity form builder service.
   * @param \Drupal\form_mode_manager\EntityRoutingMapManager $plugin_routes_manager
   *   Plugin EntityRoutingMap to retrieve entity form operation routes.
   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
   *   The form builder.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
   *   The entity type manager.
   */
  public function __construct(RendererInterface $renderer, AccountInterface $account, FormModeManagerInterface $form_mode_manager, EntityFormBuilderInterface $entity_form_builder, EntityRoutingMapManager $plugin_routes_manager, FormBuilderInterface $form_builder, EntityTypeManagerInterface $entity_manager) {
    $this->renderer = $renderer;
    $this->account = $account;
    $this->formModeManager = $form_mode_manager;
    $this->entityFormBuilder = $entity_form_builder;
    $this->entityRoutingMap = $plugin_routes_manager;
    $this->formBuilder = $form_builder;
    $this->entityTypeManager = $entity_manager;
  }

  /**
   * {@inheritdoc}
   */
  public abstract function addPage(RouteMatchInterface $route_match);

  /**
   * Retrieves entity from route match.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match.
   */
  public abstract function getEntityTypeFromRouteMatch(RouteMatchInterface $route_match);

  /**
   * Provides the entity submission form.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   */
  public abstract function getEntity(RouteMatchInterface $route_match);

  /**
   * Retrieves entity from route match.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match.
   */
  public abstract function getEntityFromRouteMatch(RouteMatchInterface $route_match);

  /**
   * {@inheritdoc}
   *
   * @return \Drupal\Core\Access\AccessResult
   *   If form mode is active, isAllowed() will be TRUE, otherwise isForbidden()
   *   will be TRUE.
   */
  public function checkAccess(RouteMatchInterface $route_match) {
    $route_object = $route_match
      ->getRouteObject();

    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $this
      ->getEntityFromRouteMatch($route_match);
    $bundle_id = $this
      ->getBundleEntityTypeId($entity, $route_match);
    $form_mode_id = $route_object
      ->getDefault('_entity_form');
    $cache_tags = $this->formModeManager
      ->getListCacheTags();

    // When we need to check access for actions links,
    // we don't have entity to load.
    if (empty($entity)) {
      $entity_type_id = $route_object
        ->getOption('_form_mode_manager_entity_type_id');
    }
    $entity_type_id = isset($entity_type_id) ? $entity_type_id : $entity
      ->getEntityTypeId();
    $operation = $this
      ->getFormModeOperationName($this->formModeManager
      ->getFormModeMachineName($form_mode_id));
    $is_active_form_mode = $this->formModeManager
      ->isActive($entity_type_id, $bundle_id, $operation);
    return AccessResult::allowedIf($is_active_form_mode)
      ->addCacheTags($cache_tags)
      ->addCacheableDependency($entity);
  }

  /**
   * {@inheritdoc}
   *
   * @return string
   *   The bundle entity type id or entity type id of entity.
   */
  public function getBundleEntityTypeId(EntityInterface $entity, RouteMatchInterface $route_match) {
    $route = $route_match
      ->getRouteObject();
    $entity_type_id = $route
      ->getOption('_form_mode_manager_entity_type_id');
    if (method_exists($entity, 'bundle') && !empty($entity
      ->bundle())) {
      return $entity
        ->bundle();
    }
    return $entity_type_id;
  }

  /**
   * {@inheritdoc}
   */
  public function entityAdd(RouteMatchInterface $route_match) {
    $entity = $this
      ->getEntity($route_match);
    $operation = $this
      ->getOperation($route_match, $entity
      ->getEntityTypeId());
    if ($entity instanceof EntityInterface) {
      return $this
        ->getForm($entity, $operation);
    }
    throw new \Exception("Entity retrieve from route isn't an instance of EntityInterface.");
  }

  /**
   * {@inheritdoc}
   */
  public function entityEdit(RouteMatchInterface $route_match) {
    $entity = $this
      ->getEntity($route_match);
    $operation = $this
      ->getOperation($route_match, $entity
      ->getEntityTypeId(), 'edit');
    if ($entity instanceof EntityInterface) {
      return $this
        ->getForm($entity, $operation);
    }
    throw new \Exception("Entity retrieve from route isn't an instance of EntityInterface.");
  }

  /**
   * {@inheritdoc}
   *
   * @return string
   *   The title context for "add" form.
   */
  public function addPageTitle(RouteMatchInterface $route_match) {
    return $this
      ->pageTitle($route_match, $this
      ->t('Create'));
  }

  /**
   * {@inheritdoc}
   *
   * @return string
   *   The title context for "edit" form.
   */
  public function editPageTitle(RouteMatchInterface $route_match) {
    return $this
      ->pageTitle($route_match, $this
      ->t('Edit'));
  }

  /**
   * The _title_callback for the entity.add routes.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   * @param string $operation
   *   Name of current context operation to display title (create/edit).
   *
   * @return string
   *   The page title.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   */
  public function pageTitle(RouteMatchInterface $route_match, $operation) {

    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity_properties = $this
      ->getEntityTypeFromRouteMatch($route_match);
    $form_mode_label = $route_match
      ->getRouteObject()
      ->getOption('parameters')['form_mode']['label'];

    /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
    $entity_type = $this->entityTypeManager
      ->getStorage($entity_properties['entity_type_id'])
      ->getEntityType();
    $name = strtolower($entity_type
      ->getLabel());
    if (!empty($entity_properties['bundle'])) {
      $name = $entity_properties['bundle'];
    }
    return $this
      ->t('@op @name as @form_mode_label', [
      '@name' => $name,
      '@form_mode_label' => $form_mode_label,
      '@op' => $operation,
    ]);
  }

  /**
   * Retrieve the operation (form mode) name in edit context.
   *
   * In Form Mode Manager all edit routes use a contextual FormClass to provide,
   * a FormClass handler different by context (add/edit).
   *
   * @param string $operation
   *   The form mode id with contextual prefix.
   *
   * @return string
   *   The name of default fallback operation.
   */
  public function getFormModeOperationName($operation) {
    return preg_replace('/^(' . FormModeManagerInterface::EDIT_PREFIX . ')|(' . FormModeManagerInterface::ADD_PREFIX . ')/', '', $operation);
  }

  /**
   * Return the correct form mode name for given contexts ($op).
   *
   * To separate things Form mode manager need to contextualize form mode by,
   * operation (edit). Because this module permit to make difference and,
   * override FormClass used by add/edit operation. In drupal add and edit,
   * are declared in annotation at EntityPlugin basis but this module make,
   * possible to change that annotation and use form mode specifically,
   * for one form mode.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   * @param string $entity_type_id
   *   The type of $entity; e.g. 'node' or 'user'.
   * @param string $op
   *   The entity form operation name.
   *
   * @return string
   *   The correct form mode name depends of given operation.
   *
   * @throws \Exception
   *   If an invalid entity is retrieving from the route object.
   */
  public function getOperation(RouteMatchInterface $route_match, $entity_type_id, $op = '') {
    $form_mode_id = $this->formModeManager
      ->getFormModeMachineName($route_match
      ->getRouteObject()
      ->getOption('parameters')['form_mode']['id']);

    /** @var \Drupal\form_mode_manager\EntityRoutingMapBase $entity_routes_infos */
    $entity_routes_infos = $this->entityRoutingMap
      ->createInstance($entity_type_id, [
      'entityTypeId' => $entity_type_id,
    ])
      ->getPluginDefinition();
    if ($op === 'edit') {
      return empty($form_mode_id) ? $entity_routes_infos
        ->getDefaultFormClass() : FormModeManagerInterface::EDIT_PREFIX . $form_mode_id;
    }
    return empty($form_mode_id) ? $entity_routes_infos
      ->getDefaultFormClass() : FormModeManagerInterface::ADD_PREFIX . $form_mode_id;
  }

  /**
   * Gets the built and processed entity form for the given entity.
   *
   * This method are very similar to EntityFormBuilderInterface::getForm,
   * for this module we need to add two form handler by form mode eg :
   * form_mode_1 => EntityFormClass
   * edit_form_mode_1 => EntityFormClass
   * to provide ability to define different EntityForm class for form,
   * for add/edit (or others) contexts.
   * Actually EntityFormBuilderInterface::getForm are designed to only have,
   * one operation (form mode) by action (add/edit/xxxx).
   *
   * In that method we use $operation parameter to retrieve the correct,
   * FormObject with our context prefixed by 'edit_' or not and in next step we,
   * set the correct Operation form with only the form mode name,
   * with ->setOperation() method onto FormObject.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to be created or edited.
   * @param string $operation
   *   (optional) The operation identifying the form variation to be returned.
   *   Defaults to 'default'. This is typically used in routing:.
   * @param array $form_state_additions
   *   (optional) An associative array used to build the current state of the
   *   form. Use this to pass additional information to the form, such as the
   *   langcode. Defaults to an empty array.
   *
   * @return array
   *   The entity Form.
   *
   * @throws \Drupal\Core\Form\FormAjaxException
   *   Thrown when a form is triggered via an AJAX submission. It will be
   *   handled by \Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber.
   * @throws \Drupal\Core\Form\EnforcedResponseException
   *   Thrown when a form builder returns a response directly, usually a
   *   \Symfony\Component\HttpFoundation\RedirectResponse. It will be handled by
   *   \Drupal\Core\EventSubscriber\EnforcedFormResponseSubscriber.
   */
  public function getForm(EntityInterface $entity, $operation = 'default', array $form_state_additions = []) {
    $form_object = $this->entityTypeManager
      ->getFormObject($entity
      ->getEntityTypeId(), $operation);
    $form_object
      ->setEntity($entity)
      ->setOperation($this
      ->getFormModeOperationName($operation));
    $form_state = (new FormState())
      ->setFormState($form_state_additions);
    return $this->formBuilder
      ->buildForm($form_object, $form_state);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AbstractEntityFormModesFactory::$account protected property The current user.
AbstractEntityFormModesFactory::$dateFormatter protected property The date formatter service.
AbstractEntityFormModesFactory::$entityFormBuilder protected property The entity form builder service.
AbstractEntityFormModesFactory::$entityRoutingMap protected property The Routes Manager Plugin.
AbstractEntityFormModesFactory::$entityTypeManager protected property The entity type manager service.
AbstractEntityFormModesFactory::$formBuilder protected property The form builder.
AbstractEntityFormModesFactory::$formModeManager protected property The entity display repository.
AbstractEntityFormModesFactory::$renderer protected property The renderer service.
AbstractEntityFormModesFactory::addPage abstract public function Displays add content links for available entity types. Overrides EntityFormModeManagerInterface::addPage 2
AbstractEntityFormModesFactory::addPageTitle public function Overrides EntityFormModeManagerInterface::addPageTitle
AbstractEntityFormModesFactory::checkAccess public function Overrides EntityFormModeManagerInterface::checkAccess 1
AbstractEntityFormModesFactory::editPageTitle public function Overrides EntityFormModeManagerInterface::editPageTitle
AbstractEntityFormModesFactory::entityAdd public function Provides the entity add submission form. Overrides EntityFormModeManagerInterface::entityAdd
AbstractEntityFormModesFactory::entityEdit public function Provides the entity 'edit' form. Overrides EntityFormModeManagerInterface::entityEdit
AbstractEntityFormModesFactory::getBundleEntityTypeId public function
AbstractEntityFormModesFactory::getEntity abstract public function Provides the entity submission form. 2
AbstractEntityFormModesFactory::getEntityFromRouteMatch abstract public function Retrieves entity from route match. 2
AbstractEntityFormModesFactory::getEntityTypeFromRouteMatch abstract public function Retrieves entity from route match. 2
AbstractEntityFormModesFactory::getForm public function Gets the built and processed entity form for the given entity.
AbstractEntityFormModesFactory::getFormModeOperationName public function Retrieve the operation (form mode) name in edit context.
AbstractEntityFormModesFactory::getOperation public function Return the correct form mode name for given contexts ($op).
AbstractEntityFormModesFactory::pageTitle public function The _title_callback for the entity.add routes.
AbstractEntityFormModesFactory::__construct public function Constructs a EntityFormModeController object.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.