API page: https://api.drupal.org/api/drupal/core%21includes%21form.inc/group/form_...

Enter a descriptive title (above) relating to Form generation, then describe the problem you have found:

We need a better topic here that explains form classes and how to use them.

See also #2148255: [meta] Make better D8 api.d.o landing page, linked to high-level overview topics, and put it in Core api.php files since this is a top-level landing topic. I think we should repurpose this existing topic page to be the place to explain how to use the new form classes etc.

Comments

jhodgdon’s picture

jhodgdon’s picture

Issue tags: +beta target
eojthebrave’s picture

Status: Active » Needs review
StatusFileSize
new5.95 KB

I took a stab at re-writing this.

jhodgdon’s picture

Status: Needs review » Needs work

Thanks! This looks mostly excellent! A few proofreading-type things to fix:

a) Whenever you refer to a namespaced class in docs, it needs to start with \. For example:

+ * Forms are defined as classes that implement the Drupal\Core\Form\FormInterface
+ * and are built using the Drupal\Core\Form\FormBuilder class. Drupal provides a

in both lines it should be \Drupal\Core\....

b) Pet grammar/puncutation peeve [I had a postdoc advisor who was a stickler for this, "some years ago"]:

...
+ * couple of utility classes which can be extended as a starting point for most
...

You either need to change "which" to "that", or precede it by a comma. The only exception would be in "of which".

c)

+ * and are built using the Drupal\Core\Form\FormBuilder class. Drupal provides a
+ * couple of utility classes which can be extended as a starting point for most
+ * basic forms the most commonly used of which is Drupal\Core\Form\FormBase.

In that 3rd line, I think a comma after "forms" would be helpful? Or a semicolon, which would let you make a complete sentence for the 2nd clause, and completely remove the "of which" there? Check the rest of the patch too -- a couple of other spots.

d)

+ * FormBuilder handles the low level processing of forms such as rendering the
+ * necessary HTML, initial processing of incoming $_POST data and delegating to
+ * your implementation of FormInterface for validation and processing of
+ * submitted data.

Oxford comma -- in a list of "a, b, and c" or "a, b, or c", we require a comma before the "and" or "or" [here, the "and" on the 2nd line]. Also do you think a comma would be helpful before "such as" in the first line?

e)

+ * \Drupal::formBuilder()->getForm() should be used to handle retrieving,
+ * processing, and displaying a rendered HTML form.
+ *
+ * Here is an example of how to use \Drupal::formBuilder()->getForm() and a form
+ * class:

I'd make these into one paragraph? Also, in the example code that follows, there is no call to ->getForm(). I think I'd just add a line (after a blank line) at the end with that call, rather than just explaining it in the following paragraph, or else move the example up and preface it with "Here's an example of a form class", because it doesn't illustrate ->getForm().

Actually... Maybe it would be good to move it quite a bit up.... Up here:

+ * Forms are defined as classes that implement the Drupal\Core\Form\FormInterface
+ * and are built using the Drupal\Core\Form\FormBuilder class. Drupal provides a
+ * couple of utility classes which can be extended as a starting point for most
+ * basic forms the most commonly used of which is Drupal\Core\Form\FormBase.

How about leaving FormBuilder out of the text there, and just talking about form classes first, and then giving the form class example? Then you can start a new section and talk about the FormBuilder and ->getForm() stuff separately, instead of trying to merge them into one example and discussion? Most people don't really need to know about the FormBuilder class anyway -- they just need to know how to make a form class and how to call getForm() to display it, right? And many uses don't actually need to know about getForm(), because they'll be using a FormController class as the page controller...

f) By the way you can put section headers into API docs now, and make links to them, with @section, @subsection, and @ref:
https://drupal.org/node/1354#section
https://drupal.org/node/1354#ref
Could be useful?

g)

+ * Given the ExampleForm defined above \Drupal::formBuilder()->getForm('example_form')
+ * would return the rendered HTML of the form defined by ExampleForm::buildForm()
+ * or call the validateForm() and submitForm() methods depending on the current
+ * processing state.

A couple of commas would make this long sentence easier to parse? Or separate into several sentences?

h)

+ * Alternatively forms can be built directly via the routing system which will
+ * take care of calling \Drupal::formBuilder()->getForm().

You really don't like commas, do you? :) I would suggest one after Alternatively here.

This really would be a good place for a @section. How about one section about form classes, one about building forms, and one about form controllers?

i)

+ * Alternatively forms can be built directly via the routing system which will
+ * take care of calling \Drupal::formBuilder()->getForm().
+ *
+ * @code
+ * example.form:
+ * path: '/example-form'
+ * defaults:
+ *   _title: 'Example form'
+ *   _form: '\Drupal\example\Form\ExampleForm'
+ * @endcode
+ *

This doesn't explicitly say it's an example that should go into a routing.yml file, maybe it should? Also, I believe if you do this, you need to make ExampleForm extend a different class (a form controller class), not just BaseForm? Check on this...

tim.plunkett’s picture

  1. +++ b/core/includes/form.inc
    @@ -38,71 +38,106 @@
    + * class ExampleForm extends FormBase {
    

    You should include a namespace, like namespace Drupal\mymodule\Form;

  2. +++ b/core/includes/form.inc
    @@ -38,71 +38,106 @@
    + *     $form['phone_number'] = array(
    + *      '#type' => 'tel',
    + *      '#title' => $this->t('Your phone number')
    + *      );
    + *    return $form;
    + *   }
    

    The indentation is off here. the FAPI keys need 1 more space, the ); needs one less, and the return $form needs one more.

  3. +++ b/core/includes/form.inc
    @@ -38,71 +38,106 @@
    + * Given the ExampleForm defined above \Drupal::formBuilder()->getForm('example_form')
    ...
    + * The argument to \Drupal::formBuilder()->getForm() is the unique ID of the
    + * form which should match the string returned from ExampleForm::getFormID().
    

    This is actually incorrect. The form ID from getFormId() is used for the actual resulting HTML, as well as for hook_form_FORM_ID_alter. getForm only takes string names now for legacy non-OO form functions, and that will be removed.

    The preferred argument would be the classname itself, as a string ('Drupal\mymodule\Form\ExampleForm'). In very special cases, you may need to manipulate the form object before buildForm is called, in which case you can do $form_object = new \Drupal\mymodule\Form\ExampleForm($something_special); $form_builder->getForm($form_object);

  4. +++ b/core/includes/form.inc
    @@ -38,71 +38,106 @@
    + * Any additional arguments based to the getForm() method will be passed along
    

    I think based should be passed

  5. +++ b/core/includes/form.inc
    @@ -38,71 +38,106 @@
    + * public function buildForm($form, &$form_state, $extra) {
    

    This must be public function buildForm(array $form, array &$form_state, $extra = NULL) {

    The = NULL and array typehints are mandatory.

Also, I believe if you do this, you need to make ExampleForm extend a different class (a form controller class), not just BaseForm? Check on this...

Not true, it's fine as is. You would only need something special if you were using _content for some reason, but the purpose of _form in the routing yaml is to make this work with no modifications needed to the class

eojthebrave’s picture

Status: Needs work » Needs review
StatusFileSize
new6.19 KB
new5.01 KB

Thanks for the review and the great feedback. I've done my best to incorporate all of it into the patch. Tim, I think the bit about advanced methods for form retrieval are probably better suited for https://drupal.org/node/2117411 than form.inc. I'll work on getting your feedback added there next. As well as updating that page which has the same wrong usage of $form_builder->getForm().

eojthebrave’s picture

StatusFileSize
new6.23 KB

There was a missing use statement. This adds use Drupal\Core\Form\FormBase; to the code example. Now I think this is really ready to go. :)

jhodgdon’s picture

Status: Needs review » Needs work

Much better, thanks!

A few minor notes:

a) Normally, we don't want a blank line after a @section line.

+ * @section generating_forms Creating forms
  *

b) Normally, after a : we don't want a blank line.

+ * Here is an example of a Form class:
  *

c) Extra comma here after validateForm(), and I think it needs one after submiForm() instead:

+ * or call the validateForm(), and submitForm() methods depending on the current

d) Colon after "method" instead of ending in . -- or maybe say "For example:

+ * getForm() method will be passed along as additional arguments to the
+ * ExampleForm::buildForm() method.
+ *
  * @code

e) same as (d) -- colon:

+ * demonstrates the use of a routing.yml file to display a form at the the
+ * given route.
+ *
+ * @code

f) I think this needs some indentation:

+ * @code
+ * example.form:
+ * path: '/example-form'
+ * defaults:
+ *   _title: 'Example form'
+ *   _form: '\Drupal\mymodule\Form\ExampleForm'
+ * @endcode

(path and defaults should be indented two spaces, right?)

Other than those minor fixes, I think this looks very good!

eojthebrave’s picture

Status: Needs work » Needs review
StatusFileSize
new6.25 KB
new1.98 KB

Thanks for the feedback. Here's the cleaned up version.

tim.plunkett’s picture

Technically it's fine, I'll leave it to @jhodgdon to sign off on the docs part. Thanks @eojthebrave!

jhodgdon’s picture

Status: Needs review » Reviewed & tested by the community

Excellent work! Docs part is good too.

jhodgdon’s picture

Status: Reviewed & tested by the community » Fixed

Thanks again! I found a couple of lines that were longer than 80 characters, and fixed the wrapping at commit time. Committed to 8.x.

  • Commit 31d1114 on 8.x by jhodgdon:
    Issue #2191429 by eojthebrave, tim.plunkett: Fix up Form API topic docs...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.