class AutosaveFormBuilder in Autosave Form 8
Provides form building and processing with AutosaveForm enabled.
Hierarchy
- class \Drupal\Core\Form\FormBuilder implements FormBuilderInterface, FormCacheInterface, FormSubmitterInterface, FormValidatorInterface, TrustedCallbackInterface
- class \Drupal\autosave_form\Form\AutosaveFormBuilder uses AutosaveButtonClickedTrait
Expanded class hierarchy of AutosaveFormBuilder
1 string reference to 'AutosaveFormBuilder'
1 service uses AutosaveFormBuilder
File
- src/
Form/ AutosaveFormBuilder.php, line 30
Namespace
Drupal\autosave_form\FormView source
class AutosaveFormBuilder extends FormBuilder {
use AutosaveButtonClickedTrait;
/**
* The form builder service.
*
* @var \Drupal\Core\Form\FormBuilderInterface
*/
protected $formBuilder;
/**
* The autosave form storage.
*
* @var \Drupal\autosave_form\Storage\AutosaveEntityFormStorageInterface
*/
protected $autosaveEntityFormStorage;
/**
* Controls whether to execute ::doBuildForm or not.
*
* If set to FALSE the normal form processing will run, otherwise if set to
* TRUE doBuildForm will not be executed. This is useful in the use case
* where we don't need the processed form like in e.g. autosave submit after
* having already at least one autosave state, from which point we don't need
* the form state values, but only the user input and the last cached form
* state.
*
* @var bool
*/
protected $doBuildFormSkip = FALSE;
/**
* Constructs a new FormBuilder.
*
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
* The form builder service.
* @param \Drupal\Core\Form\FormValidatorInterface $form_validator
* The form validator.
* @param \Drupal\Core\Form\FormSubmitterInterface $form_submitter
* The form submission processor.
* @param \Drupal\Core\Form\FormCacheInterface $form_cache
* The form cache.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
* The class resolver.
* @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
* The element info manager.
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
* The theme manager.
* @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
* The CSRF token generator.
* @param \Drupal\autosave_form\Storage\AutosaveEntityFormStorageInterface $autosave_entity_form_storage
* The autosave form storage service.
*/
public function __construct(FormBuilderInterface $form_builder, FormValidatorInterface $form_validator, FormSubmitterInterface $form_submitter, FormCacheInterface $form_cache, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, RequestStack $request_stack, ClassResolverInterface $class_resolver, ElementInfoManagerInterface $element_info, ThemeManagerInterface $theme_manager, CsrfTokenGenerator $csrf_token = NULL, AutosaveEntityFormStorageInterface $autosave_entity_form_storage) {
parent::__construct($form_validator, $form_submitter, $form_cache, $module_handler, $event_dispatcher, $request_stack, $class_resolver, $element_info, $theme_manager, $csrf_token);
$this->formBuilder = $form_builder;
$this->autosaveEntityFormStorage = $autosave_entity_form_storage;
}
public function buildForm($form_id, FormStateInterface &$form_state) {
$form = parent::buildForm($form_id, $form_state);
if ($form_state::hasAnyErrors()) {
// Under circumstances it might happen that the form is submitted but
// returned with validation errors and the form alter hooks are executed
// thus leading to the autosave form alter code being executed as well and
// putting the autosave resume/discard message to the form, which should
// not happen if the form is being returned to the browser with validation
// errors. In order to prevent this we have to add the resume/discard
// message and options only on HTTP GET requests or on POST requests if
// restore or reject submit operations have been performed or in a more
// complex case if the message has not been yet confirmed but other
// AJAX / POST requests are being triggered in the background. As we could
// not detect the last case we still put the form elements into the form,
// but on the client side we will not show the message if the form is
// returned with validation errors.
$form['#attached']['drupalSettings']['autosaveForm']['formHasErrors'] = TRUE;
// Additionally unset the form elements and settings which might have been
// added, but aren't actually needed.
unset($form['#attached']['drupalSettings']['autosaveForm']['message']);
unset($form[AutosaveFormInterface::AUTOSAVE_RESTORE_ELEMENT_NAME]);
unset($form[AutosaveFormInterface::AUTOSAVE_REJECT_ELEMENT_NAME]);
unset($form['autosave_restore_discard']);
}
return $form;
}
/**
* {@inheritdoc}
*/
public function processForm($form_id, &$form, FormStateInterface &$form_state) {
if ($this
->isAutosaveTriggered($form_state)) {
// @todo should we add a condition, that the form state is already cached
// in order to stop fully processing the form?
$this->doBuildFormSkip = TRUE;
// As we'll skip doBuildForm we have to take care of setting the
// triggering element.
$form_state
->setTriggeringElement($form[AutosaveFormInterface::AUTOSAVE_ELEMENT_NAME]);
// Needed to execute the submit handler, as this will not be done if
// duBuildForm is not being executed.
$form_state
->setSubmitHandlers($form[AutosaveFormInterface::AUTOSAVE_ELEMENT_NAME]['#submit']);
$form_state
->setProcessInput();
$form_state
->setSubmitted();
}
$response = parent::processForm($form_id, $form, $form_state);
$this->doBuildFormSkip = FALSE;
return $response;
}
/**
* {@inheritdoc}
*/
public function doBuildForm($form_id, &$element, FormStateInterface &$form_state) {
return $this->doBuildFormSkip ? $element : parent::doBuildForm($form_id, $element, $form_state);
}
/**
* {@inheritdoc}
*/
public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form = NULL) {
$this
->restoreAutosavedState($form_id, $form_state);
return parent::rebuildForm($form_id, $form_state, $old_form);
}
/**
* Restores an autosaved form state.
*
* @param $form_id
* The form id.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
protected function restoreAutosavedState($form_id, FormStateInterface $form_state) {
if (!$form_state
->get('autosave_form_restored') && ($autosaved_timestamp = $form_state
->get('autosave_form_state_timestamp'))) {
$form_object = $form_state
->getFormObject();
// Restore entity form.
if ($form_object instanceof EntityFormInterface) {
$entity = $form_object
->getEntity();
$autosaved_state = $this->autosaveEntityFormStorage
->getEntityAndFormState($form_id, $entity
->getEntityTypeId(), $entity
->id(), $entity
->language()
->getId(), $this
->currentUser()
->id(), NULL, $autosaved_timestamp);
if (is_null($autosaved_state)) {
// @todo Cover the case that the autosaved state has been purged
// meanwhile.
return;
}
/** @var EntityInterface $autosaved_entity */
$autosaved_entity = $autosaved_state['entity'];
/** @var FormStateInterface $autosaved_form_state */
$autosaved_form_state = $autosaved_state['form_state'];
// Restore the form with the entity from the autosaved state.
$form_object
->setEntity($autosaved_entity);
// Restore the user input.
$current_user_input = $form_state
->getUserInput();
$autosaved_user_input = $autosaved_form_state
->getUserInput();
// We have to rebuild the form and keep the generated form token
// instead of putting the one from the autosaved input, otherwise the
// form builder will set an form state error and, which is going to
// result into an exception, as setting form state errors after the
// validation phase is forbidden.
if (isset($current_user_input['form_token'])) {
$autosaved_user_input['form_token'] = $current_user_input['form_token'];
}
$form_state
->setUserInput($autosaved_user_input);
// Recover the form state storage, which is needed to continue from the
// state at which the form was left.
$form_state
->setStorage($autosaved_form_state
->getStorage());
// Flag the form state as being restored from autosave.
$form_state
->set('autosave_form_restored', TRUE);
}
elseif ($form_object instanceof FormInterface) {
// @todo add support for regular forms.
}
}
}
/**
* {@inheritdoc}
*/
public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
$prevent_hooks = FALSE;
if ($this
->isAutosaveTriggered($form_state)) {
// There is no need of generating a new form build id after triggering
// autosave.
$form['#build_id'] = $form_state
->getUserInput()['form_build_id'];
if ($form_state
->isCached()) {
$prevent_hooks = TRUE;
}
}
if ($prevent_hooks) {
// Prevent running hooks.
$module_handler = $this->moduleHandler;
$theme_manager = $this->themeManager;
$this->moduleHandler = new ModuleHandlerEmptyAlter();
$this->themeManager = new ThemeManagerEmptyAlter();
}
parent::prepareForm($form_id, $form, $form_state);
if ($prevent_hooks) {
$this->moduleHandler = $module_handler;
$this->themeManager = $theme_manager;
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
AutosaveButtonClickedTrait:: |
protected | function | Checks if the submission is triggered by autosave save. | |
AutosaveButtonClickedTrait:: |
protected | function | Checks if autosave restore has been triggered. | |
AutosaveButtonClickedTrait:: |
protected | function | Checks if autosave restore has been triggered. | |
AutosaveFormBuilder:: |
protected | property | The autosave form storage. | |
AutosaveFormBuilder:: |
protected | property | Controls whether to execute ::doBuildForm or not. | |
AutosaveFormBuilder:: |
protected | property | The form builder service. | |
AutosaveFormBuilder:: |
public | function |
Builds and processes a form for a given form ID. Overrides FormBuilder:: |
|
AutosaveFormBuilder:: |
public | function |
Builds and processes all elements in the structured form array. Overrides FormBuilder:: |
|
AutosaveFormBuilder:: |
public | function |
Prepares a structured form array. Overrides FormBuilder:: |
|
AutosaveFormBuilder:: |
public | function |
Processes a form submission. Overrides FormBuilder:: |
|
AutosaveFormBuilder:: |
public | function |
Constructs a new $form from the information in $form_state. Overrides FormBuilder:: |
|
AutosaveFormBuilder:: |
protected | function | Restores an autosaved form state. | |
AutosaveFormBuilder:: |
public | function |
Constructs a new FormBuilder. Overrides FormBuilder:: |
|
FormBuilder:: |
protected | property | The class resolver. | |
FormBuilder:: |
protected | property | The CSRF token generator to validate the form token. | |
FormBuilder:: |
protected | property | The current user. | |
FormBuilder:: |
protected | property | The element info manager. | |
FormBuilder:: |
protected | property | The event dispatcher. | |
FormBuilder:: |
protected | property | The form cache. | |
FormBuilder:: |
protected | property | The form submitter. | |
FormBuilder:: |
protected | property | The form validator. | |
FormBuilder:: |
protected | property | The module handler. | |
FormBuilder:: |
protected | property | The request stack. | |
FormBuilder:: |
protected | property | Defines element value callables which are safe to run even when the form state has an invalid CSRF token. | |
FormBuilder:: |
protected | property | The theme manager. | |
FormBuilder:: |
protected | function | Builds the $form['#action']. | |
FormBuilder:: |
protected | function | Determines if a given button triggered the form submission. | |
FormBuilder:: |
protected | function | Gets the current active user. | |
FormBuilder:: |
public | function |
Deletes a form in the cache. Overrides FormCacheInterface:: |
|
FormBuilder:: |
public | function |
Handles the submitted form, executing callbacks and processing responses. Overrides FormSubmitterInterface:: |
|
FormBuilder:: |
protected | function | Detects if an element triggered the form submission via Ajax. | |
FormBuilder:: |
public | function |
Executes custom submission handlers for a given form. Overrides FormSubmitterInterface:: |
|
FormBuilder:: |
public | function |
Executes custom validation handlers for a given form. Overrides FormValidatorInterface:: |
|
FormBuilder:: |
public | function |
Fetches a form from the cache. Overrides FormCacheInterface:: |
|
FormBuilder:: |
protected | function | Wraps file_upload_max_size(). | |
FormBuilder:: |
public | function |
Gets a renderable form array. Overrides FormBuilderInterface:: |
|
FormBuilder:: |
public | function |
Determines the ID of a form. Overrides FormBuilderInterface:: |
|
FormBuilder:: |
protected | function | Adds the #name and #value properties of an input element before rendering. | |
FormBuilder:: |
public | function |
Redirects the user to a URL after a form has been processed. Overrides FormSubmitterInterface:: |
|
FormBuilder:: |
public | function | Renders the form CSRF token. It's a #lazy_builder callback. | |
FormBuilder:: |
public | function | Renders a form action URL. It's a #lazy_builder callback. | |
FormBuilder:: |
public | function |
Retrieves the structured array that defines a given form. Overrides FormBuilderInterface:: |
|
FormBuilder:: |
public | function |
Stores a form in the cache. Overrides FormCacheInterface:: |
|
FormBuilder:: |
public | function |
Sets a form_token error on the given form state. Overrides FormValidatorInterface:: |
|
FormBuilder:: |
public | function |
Retrieves, populates, and processes a form. Overrides FormBuilderInterface:: |
|
FormBuilder:: |
public static | function |
Lists the trusted callbacks provided by the implementing class. Overrides TrustedCallbackInterface:: |
|
FormBuilder:: |
public | function |
Validates user-submitted form data in the $form_state. Overrides FormValidatorInterface:: |
|
FormBuilder:: |
protected | function | Helper function to normalize the different callable formats. | |
FormBuilderInterface:: |
constant | Request key for AJAX forms that submit to the form's original route. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks throw exceptions. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks trigger silenced E_USER_DEPRECATION errors. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks trigger E_USER_WARNING errors. |