From 466ef999aeb2f7fde41e3fcd16d936d14243fd81 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Tue, 11 Feb 2014 11:41:53 +0000
Subject: [PATCH] Issue #2110951 by Xano: Remove hook_forms().

---
 core/lib/Drupal/Core/Form/FormBuilder.php     | 48 -----------
 .../Drupal/Core/Form/FormBuilderInterface.php | 39 ++-------
 .../Drupal/system/Tests/Form/WrapperTest.php  | 40 ---------
 core/modules/system/system.api.php            | 83 -------------------
 .../tests/modules/form_test/form_test.module  | 31 -------
 .../modules/form_test/form_test.routing.yml   |  9 --
 .../Controller/FormTestController.php         |  7 --
 .../Drupal/form_test/Form/FormTestForm.php    |  9 --
 .../Tests/Core/Form/FormBuilderTest.php       | 25 ------
 9 files changed, 6 insertions(+), 285 deletions(-)
 delete mode 100644 core/modules/system/lib/Drupal/system/Tests/Form/WrapperTest.php

diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index 18f0f53f9459..9a19f55e0185 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -98,7 +98,6 @@ class FormBuilder implements FormBuilderInterface {
   /**
    * An array of known forms.
    *
-   * @see hook_forms()
    * @see self::retrieveForms()
    *
    * @var array
@@ -495,39 +494,6 @@ public function retrieveForm($form_id, &$form_state) {
       $callback = array($form_state['build_info']['callback_object'], 'buildForm');
     }
 
-    // We first check to see if there is a valid form builder callback defined.
-    // If there is, we simply pass the arguments on to it to get the form.
-    if (!is_callable($callback)) {
-      // In cases where many form_ids need to share a central constructor
-      // function, such as the node editing form, modules can implement
-      // hook_forms(). It maps one or more form_ids to the correct constructor
-      // functions.
-      //
-      // We cache the results of that hook to save time, but that only works for
-      // modules that know all their form_ids in advance. (A module that adds a
-      // small 'rate this comment' form to each comment in a list would need a
-      // unique form_id for each one, for example.)
-      //
-      // So, we call the hook if $this->forms isn't yet populated, OR if it
-      // doesn't yet have an entry for the requested form_id.
-      if (!isset($this->forms) || !isset($this->forms[$form_id])) {
-        $this->forms = $this->moduleHandler->invokeAll('forms', array($form_id, $args));
-      }
-      $form_definition = $this->forms[$form_id];
-      if (isset($form_definition['callback arguments'])) {
-        $args = array_merge($form_definition['callback arguments'], $args);
-      }
-      if (isset($form_definition['callback'])) {
-        $callback = $form_definition['callback'];
-        $form_state['build_info']['base_form_id'] = $callback;
-      }
-      // In case $form_state['wrapper_callback'] is not defined already, we also
-      // allow hook_forms() to define one.
-      if (!isset($form_state['wrapper_callback']) && isset($form_definition['wrapper_callback'])) {
-        $form_state['wrapper_callback'] = $form_definition['wrapper_callback'];
-      }
-    }
-
     $form = array();
     // Assign a default CSS class name based on $form_id.
     // This happens here and not in self::prepareForm() in order to allow the
@@ -543,20 +509,6 @@ public function retrieveForm($form_id, &$form_state) {
     // passed explicitly.
     $args = array_merge(array($form, &$form_state), $args);
 
-    // When the passed $form_state (not using self::getForm()) defines a
-    // 'wrapper_callback', then it requests to invoke a separate (wrapping) form
-    // builder function to pre-populate the $form array with form elements,
-    // which the actual form builder function ($callback) expects. This allows
-    // for pre-populating a form with common elements for certain forms, such as
-    // back/next/save buttons in multi-step form wizards. See self::buildForm().
-    if (isset($form_state['wrapper_callback'])) {
-      $form = call_user_func_array($form_state['wrapper_callback'], $args);
-      // Put the prepopulated $form into $args.
-      $args[0] = $form;
-    }
-
-    // If $callback was returned by a hook_forms() implementation, call it.
-    // Otherwise, call the function named after the form id.
     $form = call_user_func_array($callback, $args);
     // If the form returns some kind of response, deliver it.
     if ($form instanceof Response) {
diff --git a/core/lib/Drupal/Core/Form/FormBuilderInterface.php b/core/lib/Drupal/Core/Form/FormBuilderInterface.php
index ad6febf8da34..61294f0ccd26 100644
--- a/core/lib/Drupal/Core/Form/FormBuilderInterface.php
+++ b/core/lib/Drupal/Core/Form/FormBuilderInterface.php
@@ -39,11 +39,7 @@ public function getFormId($form_arg, &$form_state);
    * @param \Drupal\Core\Form\FormInterface|string $form_arg
    *   A form object to use to build the form, or the unique string identifying
    *   the desired form. If $form_arg is a string and a function with that
-   *   name exists, it is called to build the form array. Modules that need to
-   *   generate the same form (or very similar forms) using different $form_ids
-   *   can implement hook_forms(), which maps different $form_id values to the
-   *   proper form constructor function. Examples may be found in node_forms(),
-   *   and search_forms().
+   *   name exists, it is called to build the form array.
    * @param ...
    *   Any additional arguments are passed on to the functions called by
    *   drupal_get_form(), including the unique form constructor function. For
@@ -68,11 +64,7 @@ public function getForm($form_arg);
    *
    * @param $form_id
    *   The unique string identifying the desired form. If a function with that
-   *   name exists, it is called to build the form array. Modules that need to
-   *   generate the same form (or very similar forms) using different $form_ids
-   *   can implement hook_forms(), which maps different $form_id values to the
-   *   proper form constructor function. Examples may be found in node_forms(),
-   *   and search_forms().
+   *   name exists, it is called to build the form array.
    * @param array $form_state
    *   An array which stores information about the form. This is passed as a
    *   reference so that the caller can use it to examine what in the form
@@ -97,8 +89,8 @@ public function getForm($form_arg);
    *       Use form_load_include() to add include files from a form constructor.
    *     - form_id: Identification of the primary form being constructed and
    *       processed.
-   *     - base_form_id: Identification for a base form, as declared in a
-   *       hook_forms() implementation.
+   *     - base_form_id: Identification for a base form, as declared in the form
+  *       class's \Drupal\Core\Form\BaseFormIdInterface::getBaseFormId() method.
    *   - rebuild_info: Internal. Similar to 'build_info', but pertaining to
    *     self::rebuildForm().
    *   - rebuild: Normally, after the entire form processing is completed and
@@ -213,14 +205,6 @@ public function getForm($form_arg);
    *     need to or should not be cached during the whole form workflow; e.g.,
    *     data that needs to be accessed during the current form build process
    *     only. There is no use-case for this functionality in Drupal core.
-   *   - wrapper_callback: Modules that wish to pre-populate certain forms with
-   *     common elements, such as back/next/save buttons in multi-step form
-   *     wizards, may define a form builder function name that returns a form
-   *     structure, which is passed on to the actual form builder function.
-   *     Such implementations may either define the 'wrapper_callback' via
-   *     hook_forms() or have to invoke self::buildForm() (instead of
-   *     self::getForm()) on their own in a custom menu callback to prepare
-   *     $form_state accordingly.
    *   Information on how certain $form_state properties control redirection
    *   behavior after form submission may be found in self::redirectForm().
    *
@@ -255,11 +239,7 @@ public function getFormStateDefaults();
    *
    * @param string $form_id
    *   The unique string identifying the desired form. If a function with that
-   *   name exists, it is called to build the form array. Modules that need to
-   *   generate the same form (or very similar forms) using different $form_ids
-   *   can implement hook_forms(), which maps different $form_id values to the
-   *   proper form constructor function. Examples may be found in node_forms()
-   *   and search_forms().
+   *   name exists, it is called to build the form array.
    * @param array $form_state
    *   A keyed array containing the current state of the form.
    * @param array|null $old_form
@@ -302,11 +282,7 @@ public function setCache($form_build_id, $form, $form_state);
    * @param \Drupal\Core\Form\FormInterface|string $form_arg
    *   A form object to use to build the form, or the unique string identifying
    *   the desired form. If $form_arg is a string and a function with that
-   *   name exists, it is called to build the form array. Modules that need to
-   *   generate the same form (or very similar forms) using different $form_ids
-   *   can implement hook_forms(), which maps different $form_id values to the
-   *   proper form constructor function. Examples may be found in node_forms()
-   *   and search_forms().
+   *   name exists, it is called to build the form array.
    * @param $form_state
    *   A keyed array containing the current state of the form. Most important is
    *   the $form_state['values'] collection, a tree of data used to simulate the
@@ -354,9 +330,6 @@ public function submitForm($form_arg, &$form_state);
    * @param string $form_id
    *   The unique string identifying the desired form. If a function
    *   with that name exists, it is called to build the form array.
-   *   Modules that need to generate the same form (or very similar forms)
-   *   using different $form_ids can implement hook_forms(), which maps
-   *   different $form_id values to the proper form constructor function.
    * @param array $form_state
    *   A keyed array containing the current state of the form, including the
    *   additional arguments to self::getForm() or self::submitForm() in the
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/WrapperTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/WrapperTest.php
deleted file mode 100644
index 142c49a544df..000000000000
--- a/core/modules/system/lib/Drupal/system/Tests/Form/WrapperTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\system\Tests\Form\WrapperTest.
- */
-
-namespace Drupal\system\Tests\Form;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Test wrapper form callbacks.
- */
-class WrapperTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('form_test');
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Form wrapper callback',
-      'description' => 'Tests form wrapper callbacks to pass a prebuilt form to form builder functions.',
-      'group' => 'Form API',
-    );
-  }
-
-  /**
-   * Tests using the form in a usual way.
-   */
-  function testWrapperCallback() {
-    $this->drupalGet('form_test/wrapper-callback');
-    $this->assertText('Form wrapper callback element output.', 'The form contains form wrapper elements.');
-    $this->assertText('Form builder element output.', 'The form contains form builder elements.');
-  }
-}
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 492c8c86579f..59dfce0fb78c 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -963,9 +963,6 @@ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * one exists) check the $form_state. The base form ID is stored under
  * $form_state['build_info']['base_form_id'].
  *
- * See hook_forms() for more information on how to implement base forms in
- * Drupal.
- *
  * Form alter hooks are called in the following order: hook_form_alter(),
  * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See
  * hook_form_alter() for more details.
@@ -981,7 +978,6 @@ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * @see hook_form_alter()
  * @see hook_form_FORM_ID_alter()
  * @see drupal_prepare_form()
- * @see hook_forms()
  */
 function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
   // Modification for the form with the given BASE_FORM_ID goes here. For
@@ -996,85 +992,6 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
   );
 }
 
-/**
- * Map form_ids to form builder functions.
- *
- * By default, when drupal_get_form() is called, the system will look for a
- * function with the same name as the form ID, and use that function to build
- * the form. If no such function is found, Drupal calls this hook. Modules
- * implementing this hook can then provide their own instructions for mapping
- * form IDs to constructor functions. As a result, you can easily map multiple
- * form IDs to a single form constructor (referred to as a 'base' form).
- *
- * Using a base form can help to avoid code duplication, by allowing many
- * similar forms to use the same code base. Another benefit is that it becomes
- * much easier for other modules to apply a general change to the group of
- * forms; hook_form_BASE_FORM_ID_alter() can be used to easily alter multiple
- * forms at once by directly targeting the shared base form.
- *
- * Two example use cases where base forms may be useful are given below.
- *
- * First, you can use this hook to tell the form system to use a different
- * function to build certain forms in your module; this is often used to define
- * a form "factory" function that is used to build several similar forms. In
- * this case, your hook implementation will likely ignore all of the input
- * arguments. See node_forms() for an example of this. Note, node_forms() is the
- * hook_forms() implementation; the base form itself is defined in node_form().
- *
- * Second, you could use this hook to define how to build a form with a
- * dynamically-generated form ID. In this case, you would need to verify that
- * the $form_id input matched your module's format for dynamically-generated
- * form IDs, and if so, act appropriately.
- *
- * @param $form_id
- *   The unique string identifying the desired form.
- * @param $args
- *   An array containing the original arguments provided to drupal_get_form()
- *   or drupal_form_submit(). These are always passed to the form builder and
- *   do not have to be specified manually in 'callback arguments'.
- *
- * @return
- *   An associative array whose keys define form_ids and whose values are an
- *   associative array defining the following keys:
- *   - callback: The name of the form builder function to invoke. This will be
- *     used for the base form ID, for example, to target a base form using
- *     hook_form_BASE_FORM_ID_alter().
- *   - callback arguments: (optional) Additional arguments to pass to the
- *     function defined in 'callback', which are prepended to $args.
- *   - wrapper_callback: (optional) The name of a form builder function to
- *     invoke before the form builder defined in 'callback' is invoked. This
- *     wrapper callback may prepopulate the $form array with form elements,
- *     which will then be already contained in the $form that is passed on to
- *     the form builder defined in 'callback'. For example, a wrapper callback
- *     could setup wizard-alike form buttons that are the same for a variety of
- *     forms that belong to the wizard, which all share the same wrapper
- *     callback.
- */
-function hook_forms($form_id, $args) {
-  // Simply reroute the (non-existing) $form_id 'mymodule_first_form' to
-  // 'mymodule_main_form'.
-  $forms['mymodule_first_form'] = array(
-    'callback' => 'mymodule_main_form',
-  );
-
-  // Reroute the $form_id and prepend an additional argument that gets passed to
-  // the 'mymodule_main_form' form builder function.
-  $forms['mymodule_second_form'] = array(
-    'callback' => 'mymodule_main_form',
-    'callback arguments' => array('some parameter'),
-  );
-
-  // Reroute the $form_id, but invoke the form builder function
-  // 'mymodule_main_form_wrapper' first, so we can prepopulate the $form array
-  // that is passed to the actual form builder 'mymodule_main_form'.
-  $forms['mymodule_wrapped_form'] = array(
-    'callback' => 'mymodule_main_form',
-    'wrapper_callback' => 'mymodule_main_form_wrapper',
-  );
-
-  return $forms;
-}
-
 /**
  * Alter an email message created with the drupal_mail() function.
  *
diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module
index 922bc784453f..c176144d5992 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -742,37 +742,6 @@ function form_label_test_form() {
   return $form;
 }
 
-/**
- * Menu callback; Invokes a form builder function with a wrapper callback.
- *
- * @deprecated \Drupal\form_test\Controller\FormTestController::wrapperCallback()
- */
-function form_test_wrapper_callback($form_id) {
-  $form_state = array(
-    'build_info' => array('args' => array()),
-    'wrapper_callback' => 'form_test_wrapper_callback_wrapper',
-  );
-  return drupal_build_form($form_id, $form_state);
-}
-
-/**
- * Form wrapper for form_test_wrapper_callback_form().
- */
-function form_test_wrapper_callback_wrapper($form, &$form_state) {
-  $form['wrapper'] = array('#markup' => 'Form wrapper callback element output.');
-  return $form;
-}
-
-/**
- * Form builder for form wrapper callback test.
- *
- * @deprecated Use \Drupal\form_test\testWrapperCallback()
- */
-function form_test_wrapper_callback_form($form, &$form_state) {
-  $form['builder'] = array('#markup' => 'Form builder element output.');
-  return $form;
-}
-
 /**
  * Form builder for form_state_values_clean() test.
  *
diff --git a/core/modules/system/tests/modules/form_test/form_test.routing.yml b/core/modules/system/tests/modules/form_test/form_test.routing.yml
index a37c9d8cb772..3540177c0c50 100644
--- a/core/modules/system/tests/modules/form_test/form_test.routing.yml
+++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml
@@ -68,15 +68,6 @@ form_test.autocomplete_2:
   requirements:
     _permission: 'access autocomplete test'
 
-form_test.wrapper:
-  path: '/form_test/wrapper-callback'
-  defaults:
-    _title: 'Form wrapper callback test'
-    _content: '\Drupal\form_test\Controller\FormTestController::wrapperCallback'
-    form_id: 'form_test_wrapper_callback_form'
-  requirements:
-    _access: 'TRUE'
-
 form_test.alter_form:
   path: '/form-test/alter'
   defaults:
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Controller/FormTestController.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Controller/FormTestController.php
index 59a119d6ad84..b7ed78c27e37 100644
--- a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Controller/FormTestController.php
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Controller/FormTestController.php
@@ -35,11 +35,4 @@ public function twoFormInstances() {
     return $return;
   }
 
-  /**
-   * @todo Remove form_test_wrapper_callback().
-   */
-  public function wrapperCallback($form_id) {
-    return form_test_wrapper_callback($form_id);
-  }
-
 }
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestForm.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestForm.php
index 6fa4ab00faee..7b139322d7de 100644
--- a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestForm.php
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestForm.php
@@ -129,15 +129,6 @@ public function testStorage() {
     return drupal_get_form('form_test_storage_form');
   }
 
-  /**
-   * Wraps form_test_wrapper_callback_form().
-   *
-   * @todo Remove form_test_wrapper_callback_form().
-   */
-  public function testWrapperCallback() {
-    return drupal_get_form('form_test_wrapper_callback_form');
-  }
-
   /**
    * Wraps form_test_form_state_values_clean_form().
    *
diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
index 4537b6e742be..487f4c83e137 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
@@ -341,31 +341,6 @@ public function testBuildFormWithObject() {
     $this->assertSame($form_id, $form['#id']);
   }
 
-  /**
-   * Tests the buildForm() method with a hook_forms() based form ID.
-   */
-  public function testBuildFormWithHookForms() {
-    $form_id = 'test_form_id_specific';
-    $base_form_id = 'test_form_id';
-    $expected_form = $base_form_id();
-    // Set the module handler to return information from hook_forms().
-    $this->moduleHandler->expects($this->once())
-      ->method('invokeAll')
-      ->with('forms', array($form_id, array()))
-      ->will($this->returnValue(array(
-        'test_form_id_specific' => array(
-          'callback' => $base_form_id,
-        ),
-      )));
-
-    $form_state = array();
-    $form = $this->formBuilder->buildForm($form_id, $form_state);
-    $this->assertFormElement($expected_form, $form, 'test');
-    $this->assertSame($form_id, $form_state['build_info']['form_id']);
-    $this->assertSame($form_id, $form['#id']);
-    $this->assertSame($base_form_id, $form_state['build_info']['base_form_id']);
-  }
-
   /**
    * Tests the rebuildForm() method.
    */
-- 
GitLab