Commit 4217221f authored by webchick's avatar webchick

Issue #2110953 by Xano, dawehner: Convert views_forms() to a classed form.

parent 30e56c5d
<?php
/**
* @file
* Contains \Drupal\views\Form\ViewsForm.
*/
namespace Drupal\views\Form;
use Drupal\Component\Utility\Url;
use Drupal\Core\Controller\ControllerResolverInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\views\ViewExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Provides a base class for single- or multistep view forms.
*
* This class only dispatches logic to the form for the current step. The form
* is always assumed to be multistep, even if it has only one step (which by
* default is \Drupal\views\Form\ViewsFormMainForm). That way it is actually
* possible for modules to have a multistep form if they need to.
*/
class ViewsForm implements FormInterface, ContainerInjectionInterface {
/**
* The controller resolver to get the subform form objects.
*
* @var \Drupal\Core\Controller\ControllerResolverInterface
*/
protected $controllerResolver;
/**
* The current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* The url generator to generate the form action.
*
* @var \Drupal\Core\Routing\UrlGeneratorInterface
*/
protected $urlGenerator;
/**
* The ID of the view.
*
* @var string
*/
protected $viewId;
/**
* The ID of the active view's display.
*
* @var string
*/
protected $viewDisplayId;
/**
* Constructs a ViewsForm object.
*
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
* The controller resolver to get the subform form objects.
* @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
* The url generator to generate the form action.
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
* @param string $view_id
* The ID of the view.
* @param string $view_display_id
* The ID of the active view's display.
*/
public function __construct(ControllerResolverInterface $controller_resolver, UrlGeneratorInterface $url_generator, Request $request, $view_id, $view_display_id) {
$this->controllerResolver = $controller_resolver;
$this->urlGenerator = $url_generator;
$this->request = $request;
$this->viewId = $view_id;
$this->viewDisplayId = $view_display_id;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL) {
return new static(
$container->get('controller_resolver'),
$container->get('url_generator'),
$container->get('request'),
$view_id,
$view_display_id
);
}
/**
* {@inheritdoc}
*/
public function getFormID() {
$parts = array(
'views_form',
$this->viewId,
$this->viewDisplayId,
);
return implode('_', $parts);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, ViewExecutable $view = NULL, $output = NULL) {
$form_state['step'] = isset($form_state['step']) ? $form_state['step'] : 'views_form_views_form';
$form_state['step_controller']['views_form_views_form'] = 'Drupal\views\Form\ViewsFormMainForm';
// Cache the built form to prevent it from being rebuilt prior to validation
// and submission, which could lead to data being processed incorrectly,
// because the views rows (and thus, the form elements as well) have changed
// in the meantime.
$form_state['cache'] = TRUE;
$form = array();
$query = $this->request->query->all();
$query = Url::filterQueryParameters($query, array(), '');
$form['#action'] = $this->urlGenerator->generateFromPath($view->getUrl(), array('query' => $query));
// Tell the preprocessor whether it should hide the header, footer, pager...
$form['show_view_elements'] = array(
'#type' => 'value',
'#value' => ($form_state['step'] == 'views_form_views_form') ? TRUE : FALSE,
);
$form_object = $this->getFormObject($form_state);
$form += $form_object->buildForm($form, $form_state, $view, $output);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
$form_object = $this->getFormObject($form_state);
$form_object->validateForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$form_object = $this->getFormObject($form_state);
$form_object->submitForm($form, $form_state);
}
/**
* Returns the object used to build the step form.
*
* @param array $form_state
* The form_state of the current form.
*
* @return \Drupal\Core\Form\FormInterface
* The form object to use.
*/
protected function getFormObject(array $form_state) {
// If this is a class, instantiate it.
$form_step_class = isset($form_state['step_controller'][$form_state['step']]) ? $form_state['step_controller'][$form_state['step']] : 'Drupal\views\Form\ViewsFormMainForm';
$container = \Drupal::getContainer();
if (class_exists($form_step_class)) {
if (in_array('Drupal\Core\DependencyInjection\ContainerInjectionInterface', class_implements($form_step_class))) {
return $form_step_class::create($container);
}
return new $form_step_class();
}
// Otherwise, it is a service.
return $container->get($form_step_class);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Form\ViewsFormMainForm.
*/
namespace Drupal\views\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\views\ViewExecutable;
class ViewsFormMainForm implements FormInterface {
/**
* {@inheritdoc}
*/
public function getFormID() {
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, ViewExecutable $view = NULL, $output = NULL) {
$form['#prefix'] = '<div class="views-form">';
$form['#suffix'] = '</div>';
$form['#theme'] = 'form';
$form['#pre_render'][] = 'views_pre_render_views_form_views_form';
// Add the output markup to the form array so that it's included when the form
// array is passed to the theme function.
$form['output'] = array(
'#markup' => $output,
// This way any additional form elements will go before the view
// (below the exposed widgets).
'#weight' => 50,
);
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
$substitutions = array();
foreach ($view->field as $field_name => $field) {
$form_element_name = $field_name;
if (method_exists($field, 'form_element_name')) {
$form_element_name = $field->form_element_name();
}
$method_form_element_row_id_exists = FALSE;
if (method_exists($field, 'form_element_row_id')) {
$method_form_element_row_id_exists = TRUE;
}
// If the field provides a views form, allow it to modify the $form array.
$has_form = FALSE;
if (property_exists($field, 'views_form_callback')) {
$callback = $field->views_form_callback;
$callback($view, $field, $form, $form_state);
$has_form = TRUE;
}
elseif (method_exists($field, 'views_form')) {
$field->views_form($form, $form_state);
$has_form = TRUE;
}
// Build the substitutions array for use in the theme function.
if ($has_form) {
foreach ($view->result as $row_id => $row) {
if ($method_form_element_row_id_exists) {
$form_element_row_id = $field->form_element_row_id($row_id);
}
else {
$form_element_row_id = $row_id;
}
$substitutions[] = array(
'placeholder' => '<!--form-item-' . $form_element_name . '--' . $form_element_row_id . '-->',
'field_name' => $form_element_name,
'row_id' => $form_element_row_id,
);
}
}
}
// Give the area handlers a chance to extend the form.
$area_handlers = array_merge(array_values($view->header), array_values($view->footer));
$empty = empty($view->result);
foreach ($area_handlers as $area) {
if (method_exists($area, 'views_form') && !$area->views_form_empty($empty)) {
$area->views_form($form, $form_state);
}
}
$form['#substitutions'] = array(
'#type' => 'value',
'#value' => $substitutions,
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
$view = $form_state['build_info']['args'][0];
// Call the validation method on every field handler that has it.
foreach ($view->field as $field) {
if (method_exists($field, 'views_form_validate')) {
$field->views_form_validate($form, $form_state);
}
}
// Call the validate method on every area handler that has it.
foreach (array('header', 'footer') as $area) {
foreach ($view->{$area} as $area_handler) {
if (method_exists($area_handler, 'views_form_validate')) {
$area_handler->views_form_validate($form, $form_state);
}
}
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$view = $form_state['build_info']['args'][0];
// Call the submit method on every field handler that has it.
foreach ($view->field as $field) {
if (method_exists($field, 'views_form_submit')) {
$field->views_form_submit($form, $form_state);
}
}
// Call the submit method on every area handler that has it.
foreach (array('header', 'footer') as $area) {
foreach ($view->{$area} as $area_handler) {
if (method_exists($area_handler, 'views_form_submit')) {
$area_handler->views_form_submit($form, $form_state);
}
}
}
}
}
......@@ -18,37 +18,6 @@
use Drupal\views\Views;
use Drupal\field\FieldInstanceInterface;
/**
* Implements hook_forms().
*
* To provide distinct form IDs for Views forms, the View name and
* specific display name are appended to the base ID,
* views_form_views_form. When such a form is built or submitted, this
* function will return the proper callback function to use for the given form.
*/
function views_forms($form_id, $args) {
if (strpos($form_id, 'views_form_') === 0) {
return array(
$form_id => array(
'callback' => 'views_form',
),
);
}
}
/**
* Returns a form ID for a Views form using the name and display of the View.
*/
function views_form_id($view) {
$parts = array(
'views_form',
$view->storage->id(),
$view->current_display,
);
return implode('_', $parts);
}
/**
* Implements hook_element_info().
*/
......@@ -1035,171 +1004,6 @@ function views_view_has_form_elements($view) {
return FALSE;
}
/**
* This is the entry function. Just gets the form for the current step.
* The form is always assumed to be multistep, even if it has only one
* step (the default 'views_form_views_form' step). That way it is actually
* possible for modules to have a multistep form if they need to.
*/
function views_form($form, &$form_state, ViewExecutable $view, $output) {
$form_state['step'] = isset($form_state['step']) ? $form_state['step'] : 'views_form_views_form';
// Cache the built form to prevent it from being rebuilt prior to validation
// and submission, which could lead to data being processed incorrectly,
// because the views rows (and thus, the form elements as well) have changed
// in the meantime.
$form_state['cache'] = TRUE;
$form = array();
$query = drupal_get_query_parameters();
$form['#action'] = url($view->getUrl(), array('query' => $query));
// Tell the preprocessor whether it should hide the header, footer, pager...
$form['show_view_elements'] = array(
'#type' => 'value',
'#value' => ($form_state['step'] == 'views_form_views_form') ? TRUE : FALSE,
);
$form = $form_state['step']($form, $form_state, $view, $output);
return $form;
}
/**
* Callback for the main step of a Views form.
* Invoked by views_form().
*/
function views_form_views_form($form, &$form_state, ViewExecutable $view, $output) {
$form['#prefix'] = '<div class="views-form">';
$form['#suffix'] = '</div>';
$form['#theme'] = 'form';
$form['#pre_render'][] = 'views_pre_render_views_form_views_form';
$form['#validate'][] = 'views_form_views_form_validate';
$form['#submit'][] = 'views_form_views_form_submit';
// Add the output markup to the form array so that it's included when the form
// array is passed to the theme function.
$form['output'] = array(
'#markup' => $output,
// This way any additional form elements will go before the view
// (below the exposed widgets).
'#weight' => 50,
);
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
$substitutions = array();
foreach ($view->field as $field_name => $field) {
$form_element_name = $field_name;
if (method_exists($field, 'form_element_name')) {
$form_element_name = $field->form_element_name();
}
$method_form_element_row_id_exists = FALSE;
if (method_exists($field, 'form_element_row_id')) {
$method_form_element_row_id_exists = TRUE;
}
// If the field provides a views form, allow it to modify the $form array.
$has_form = FALSE;
if (property_exists($field, 'views_form_callback')) {
$callback = $field->views_form_callback;
$callback($view, $field, $form, $form_state);
$has_form = TRUE;
}
elseif (method_exists($field, 'views_form')) {
$field->views_form($form, $form_state);
$has_form = TRUE;
}
// Build the substitutions array for use in the theme function.
if ($has_form) {
foreach ($view->result as $row_id => $row) {
if ($method_form_element_row_id_exists) {
$form_element_row_id = $field->form_element_row_id($row_id);
}
else {
$form_element_row_id = $row_id;
}
$substitutions[] = array(
'placeholder' => '<!--form-item-' . $form_element_name . '--' . $form_element_row_id . '-->',
'field_name' => $form_element_name,
'row_id' => $form_element_row_id,
);
}
}
}
// Give the area handlers a chance to extend the form.
$area_handlers = array_merge(array_values($view->header), array_values($view->footer));
$empty = empty($view->result);
foreach ($area_handlers as $area) {
if (method_exists($area, 'views_form') && !$area->views_form_empty($empty)) {
$area->views_form($form, $form_state);
}
}
$form['#substitutions'] = array(
'#type' => 'value',
'#value' => $substitutions,
);
return $form;
}
/**
* Validate handler for the first step of the views form.
* Calls any existing views_form_validate functions located
* on the views fields.
*/
function views_form_views_form_validate($form, &$form_state) {
$view = $form_state['build_info']['args'][0];
// Call the validation method on every field handler that has it.
foreach ($view->field as $field) {
if (method_exists($field, 'views_form_validate')) {
$field->views_form_validate($form, $form_state);
}
}
// Call the validate method on every area handler that has it.
foreach (array('header', 'footer') as $area) {
foreach ($view->{$area} as $area_handler) {
if (method_exists($area_handler, 'views_form_validate')) {
$area_handler->views_form_validate($form, $form_state);
}
}
}
}
/**
* Submit handler for the first step of the views form.
* Calls any existing views_form_submit functions located
* on the views fields.
*/
function views_form_views_form_submit($form, &$form_state) {
$view = $form_state['build_info']['args'][0];
// Call the submit method on every field handler that has it.
foreach ($view->field as $field) {
if (method_exists($field, 'views_form_submit')) {
$field->views_form_submit($form, $form_state);
}
}
// Call the submit method on every area handler that has it.
foreach (array('header', 'footer') as $area) {
foreach ($view->{$area} as $area_handler) {
if (method_exists($area_handler, 'views_form_submit')) {
$area_handler->views_form_submit($form, $form_state);
}
}
}
}
/**
* Replaces views substitution placeholders.
*
......
......@@ -8,6 +8,7 @@
use Drupal\Component\Utility\Xss;
use Drupal\Core\Language\Language;
use Drupal\Core\Template\Attribute;
use Drupal\views\Form\ViewsForm;
use Drupal\views\ViewExecutable;
/**
......@@ -134,7 +135,10 @@ function template_preprocess_views_view(&$variables) {
$rows = $variables['rows'];
$rows = drupal_render($rows);
$output = !empty($rows) ? $rows : $variables['empty'];
$form = drupal_get_form(views_form_id($view), $view, $output);
$container = \Drupal::getContainer();
$form_object = new ViewsForm($container->get('controller_resolver'), $container->get('url_generator'), $container->get('request'), $view->storage->id(), $view->current_display);
$form = \Drupal::formBuilder()->getForm($form_object, $view, $output);
// The form is requesting that all non-essential views elements be hidden,
// usually because the rendered step is not a view result.
if ($form['show_view_elements']['#value'] == FALSE) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment