forms_steps-8.x-1.4/src/Form/FormsStepsStepFormBase.php
src/Form/FormsStepsStepFormBase.php
<?php
declare(strict_types=1);
namespace Drupal\forms_steps\Form;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a base form for a Step.
*
* @package Drupal\forms_steps\Form
*/
class FormsStepsStepFormBase extends EntityForm {
/**
* The ID of the step that is being edited.
*
* @var string
*/
protected string $stepId;
/**
* EntityTypeManagerInterface.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* EntityDisplayRepositoryInterface.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected EntityDisplayRepositoryInterface $entityDisplayRepository;
/**
* EntityTypeBundleInfoInterface.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected EntityTypeBundleInfoInterface $entityTypeBundleInfo;
/**
* Class constructor.
*/
public function __construct(
EntityTypeManagerInterface $entity_type_manager,
EntityDisplayRepositoryInterface $entity_display_repository,
EntityTypeBundleInfoInterface $entity_type_bundle_info
) {
$this->entityTypeManager = $entity_type_manager;
$this->entityDisplayRepository = $entity_display_repository;
$this->entityTypeBundleInfo = $entity_type_bundle_info;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): FormsStepsStepFormBase {
// Instantiates this form class.
return new static(
// Load the service required to construct this class.
$container->get('entity_type.manager'),
$container->get('entity_display.repository'),
$container->get('entity_type.bundle.info')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $forms_steps_step = '') {
$this->stepId = $forms_steps_step;
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state): array {
$form = parent::form($form, $form_state);
/** @var \Drupal\forms_steps\Entity\FormsSteps $formsSteps */
$formsSteps = $this->getEntity();
$step = NULL;
try {
/** @var \Drupal\forms_steps\Step $entity */
$step = $formsSteps->getStep($this->stepId);
}
catch (\InvalidArgumentException $ex) {
// New step.
}
$form['label'] = [
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) ? $step->label() : '',
'#description' => $this->t('Label for the step.'),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#machine_name' => [
'exists' => [$this, 'exists'],
],
];
// @todo Remove 'node.' concatenation with step entity bundle.
// We retrieve the list of entities.
$entitiesDefinition = $this->entityTypeManager->getDefinitions();
$entitiesSelectList = [];
$fieldableInterface = 'Drupal\Core\Entity\FieldableEntityInterface';
foreach ($entitiesDefinition as $entityDefinition) {
// EntityDisplay entities can only handle fieldable entity types.
if (in_array($fieldableInterface, class_implements($entityDefinition->getOriginalClass()))) {
$entitiesSelectList[$entityDefinition->id()] = $entityDefinition->getLabel();
}
}
$selectedEntityType = $form_state->getValues()['target_entity_type'] ?? ($step ? $step->entityType() : 'node');
$form['target_entity_type'] = [
'#type' => 'select',
'#title' => $this->t('Entity Type'),
'#maxlength' => 255,
'#default_value' => $selectedEntityType,
'#description' => $this->t('Entity type (Node, User, ...)'),
'#required' => TRUE,
'#options' => $entitiesSelectList,
'#ajax' => [
'callback' => 'Drupal\forms_steps\Form\FormsStepsStepFormBase::updateFormModeCallback',
'event' => 'change',
'wrapper' => 'form-mode-container',
'progress' => [
'type' => 'throbber',
'message' => $this->t('Updating entry...'),
],
],
];
// We get the list of entity bundles.
$entityBundles = $this->entityTypeBundleInfo->getBundleInfo($selectedEntityType);
$entityBundlesSelectList = [];
foreach ($entityBundles as $entityBundleKey => $entityBundleValue) {
$entityBundlesSelectList[$entityBundleKey] = $entityBundleValue['label'];
}
$form['form_mode_container'] = [
'#type' => 'container',
'#attributes' => [
'id' => 'form-mode-container',
],
];
$selectedBundle =
!empty($form_state->getValues()['target_entity_bundle']) && isset($entityBundlesSelectList[$form_state->getValues()['target_entity_bundle']])
? $form_state->getValues()['target_entity_bundle'] : (
!is_null($step) && isset($entityBundlesSelectList[$step->entityBundle()]) ? $step->entityBundle() : key($entityBundlesSelectList)
);
$form['form_mode_container']['target_entity_bundle'] = [
'#type' => 'select',
'#title' => $this->t('Bundle'),
'#maxlength' => 255,
'#description' => $this->t('Entity type of the form.'),
'#required' => TRUE,
'#default_value' => $selectedBundle,
'#options' => $entityBundlesSelectList,
];
// We get all the form mode for the selected Entity.
$formModesSelectList = ['default' => $this->t('Default')];
if (!is_null($selectedEntityType)) {
$formModes = $this->entityDisplayRepository->getFormModes(
$selectedEntityType
);
foreach ($formModes as $formModeDefinition) {
$formModesSelectList[$formModeDefinition['id']] = $formModeDefinition['label'];
}
}
$selectedFormMode = !empty($form_state->getValues()['target_form_mode']) ? $form_state->getValues()['target_form_mode'] : ($step ? $step->formMode() : key($formModesSelectList));
$form['form_mode_container']['target_form_mode'] = [
'#type' => 'select',
'#title' => $this->t('Form mode'),
'#maxlength' => 255,
'#default_value' => $selectedFormMode,
'#description' => $this->t('Form mode of the Content type.'),
'#required' => TRUE,
'#options' => $formModesSelectList,
];
$form['url'] = [
'#type' => 'textfield',
'#title' => $this->t('Step URL'),
'#size' => 30,
'#description' => $this->t('Form step URL.'),
'#placeholder' => '/my_form/step1',
'#default_value' => $step && $step->url() ? $step->url() : '',
'#required' => TRUE,
];
$form['submit_button'] = [
'#type' => 'details',
'#title' => $this->t('Submit Button'),
'#open' => FALSE,
];
$form['submit_button']['override_submit'] = [
'#type' => 'checkbox',
'#title' => $this->t('Override submit label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->submitLabel(),
'#required' => FALSE,
];
$form['submit_button']['submit_label'] = [
'#type' => 'textfield',
'#title' => $this->t('Submit label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->submitLabel() ? $step->submitLabel() : NULL,
'#description' => $this->t('Label of the submit button.'),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="override_submit"]' => [
'checked' => TRUE,
],
],
],
];
$form['delete_button'] = [
'#type' => 'details',
'#title' => $this->t('Delete Button'),
'#open' => FALSE,
];
$form['delete_button']['hide_delete'] = [
'#type' => 'checkbox',
'#title' => $this->t('Hide delete button'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->hideDelete(),
'#required' => FALSE,
];
$form['delete_button']['override_delete'] = [
'#type' => 'checkbox',
'#title' => $this->t('Override delete label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->deleteLabel(),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="hide_delete"]' => [
'checked' => FALSE,
],
],
],
];
$form['delete_button']['delete_label'] = [
'#type' => 'textfield',
'#title' => $this->t('Delete label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->deleteLabel() ? $step->deleteLabel() : NULL,
'#description' => $this->t('Label of the delete button.'),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="override_delete"]' => [
'checked' => TRUE,
],
':input[name="hide_delete"]' => [
'checked' => FALSE,
],
],
],
];
$form['cancel_button'] = [
'#type' => 'details',
'#title' => $this->t('Cancel Button'),
'#open' => FALSE,
];
$form['cancel_button']['override_cancel'] = [
'#type' => 'checkbox',
'#title' => $this->t('Override cancel label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->cancelLabel(),
'#required' => FALSE,
];
$form['cancel_button']['cancel_label'] = [
'#type' => 'textfield',
'#title' => $this->t('Cancel label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->cancelLabel() ? $step->cancelLabel() : NULL,
'#description' => $this->t('Label of the cancel button.'),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="override_cancel"]' => [
'checked' => TRUE,
],
],
],
];
$form['cancel_button']['set_cancel_route'] = [
'#type' => 'checkbox',
'#title' => $this->t('Set cancel route'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->cancelRoute(),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="set_cancel_step"]' => [
'checked' => FALSE,
],
],
],
];
$form['cancel_button']['cancel_route'] = [
'#type' => 'textfield',
'#title' => $this->t('Cancel route'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->cancelRoute() ? $step->cancelRoute() : NULL,
'#description' => '',
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="set_cancel_route"]' => [
'checked' => TRUE,
],
],
],
];
$form['cancel_button']['set_cancel_step'] = [
'#type' => 'checkbox',
'#title' => $this->t('Set a step to go when cancel is clicked.'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->cancelStep(),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="set_cancel_route"]' => [
'checked' => FALSE,
],
],
],
];
$steps = $formsSteps->getSteps();
$steps_options = [];
/** @var \Drupal\forms_steps\Step $step */
foreach ($steps as $_step) {
$steps_options[$_step->id()] = $_step->label();
}
$form['cancel_button']['cancel_step'] = [
'#type' => 'select',
'#title' => $this->t('Step'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->cancelStep() ? $step->cancelStep()
->id() : NULL,
'#required' => FALSE,
'#options' => $steps_options,
'#states' => [
'visible' => [
':input[name="set_cancel_step"]' => [
'checked' => TRUE,
],
],
],
];
$form['previous_button'] = [
'#type' => 'details',
'#title' => $this->t('Previous Button'),
'#open' => FALSE,
];
$form['previous_button']['display_previous'] = [
'#type' => 'checkbox',
'#title' => $this->t('Display previous button'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->displayPrevious(),
'#required' => FALSE,
];
$form['previous_button']['previous_label'] = [
'#type' => 'textfield',
'#title' => $this->t('Previous label'),
'#maxlength' => 255,
'#default_value' => !is_null($step) && $step->previousLabel() ? $step->previousLabel() : NULL,
'#description' => $this->t('Label of the previous button.'),
'#required' => FALSE,
'#states' => [
'visible' => [
':input[name="display_previous"]' => [
'checked' => TRUE,
],
],
],
];
return $form;
}
/**
* Copies top-level form values to entity properties.
*
* This form can only change values for a step, which is part of forms_steps.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity the current form should operate upon.
* @param array $form
* A nested array of form elements comprising the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
if ($form_state->isSubmitted()) {
/** @var \Drupal\forms_steps\FormsStepsInterface $entity */
$values = $form_state->getValues();
if (!$entity->hasStep($values['id'])) {
$entity->addStep(
$values['id'], $values['label'], $values['target_entity_type'],
$values['target_entity_bundle'], $values['target_form_mode'],
$values['url']
);
}
if (!empty($values['label'])) {
$entity->setStepLabel($values['id'], $values['label']);
}
if (!empty($values['target_entity_type'])) {
$entity->setStepEntityType(
$values['id'],
$values['target_entity_type']
);
}
if (!empty($values['target_entity_bundle'])) {
$entity->setStepEntityBundle($values['id'], $values['target_entity_bundle']);
}
if (!empty($values['target_form_mode'])) {
$entity->setStepFormMode($values['id'], $values['target_form_mode']);
}
if (!empty($values['url'])) {
$entity->setStepUrl($values['id'], $values['url']);
}
if ($values['override_submit'] == 1) {
$entity->setStepSubmitLabel($values['id'], $values['submit_label']);
}
else {
$entity->setStepSubmitLabel($values['id'], '');
}
if ($values['hide_delete'] == 1) {
$entity->setStepDeleteState($values['id'], TRUE);
}
else {
$entity->setStepDeleteState($values['id'], FALSE);
if ($values['override_delete'] == 1) {
$entity->setStepDeleteLabel($values['id'], $values['delete_label']);
}
else {
$entity->setStepDeleteLabel($values['id'], NULL);
}
}
if ($values['override_cancel'] == 1) {
$entity->setStepCancelLabel($values['id'], $values['cancel_label']);
if ($values['set_cancel_route'] == 1) {
$entity->setStepCancelStep($values['id'], NULL);
$entity->setStepCancelStepMode($values['id'], '');
$entity->setStepCancelRoute($values['id'], $values['cancel_route']);
}
else {
if ($values['set_cancel_step'] == 1) {
$entity->setStepCancelRoute($values['id'], '');
$entity->setStepCancelStep(
$values['id'],
$entity->getStep($values['cancel_step'])
);
}
}
}
else {
$entity->setStepCancelLabel($values['id'], '');
}
if ($values['display_previous'] == 1) {
$entity->setStepPreviousState($values['id'], TRUE);
$entity->setStepPreviousLabel($values['id'], $values['previous_label']);
}
else {
$entity->setStepPreviousState($values['id'], FALSE);
}
}
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if ($form_state->isSubmitted()) {
parent::validateForm($form, $form_state);
$values = $form_state->getValues();
$entityFormDisplay =
\Drupal::service('entity_display.repository')->getFormDisplay(
$values['target_entity_type'],
$values['target_entity_bundle'],
preg_replace(
"/^{$values['target_entity_type']}\./",
'',
$values['target_form_mode']
)
);
if ($entityFormDisplay->isNew()) {
$form_state->setErrorByName(
'target_form_mode',
$this->t('This form mode is not yet defined for the selected bundle.')
);
}
}
}
/**
* Determines if the forms steps step already exists.
*
* @param string $step_id
* The forms steps step ID.
*
* @return bool
* TRUE if the forms steps step exists, FALSE otherwise.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function exists(string $step_id): bool {
/** @var \Drupal\forms_steps\FormsStepsInterface $original_forms_steps */
$original_forms_steps = $this->entityTypeManager
->getStorage('forms_steps')
->loadUnchanged($this->getEntity()->id());
return $original_forms_steps->hasStep($step_id);
}
/**
* Callback to return new nested select values.
*
* @param array $form
* The referenced form to use.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form_state.
*
* @return array
* Returns the new form_mode_container based on the change done in Ajax.
*/
public static function updateFormModeCallback(array &$form, FormStateInterface $form_state) : array {
$form_state->setRebuild();
return $form['form_mode_container'];
}
}
