Problem/Motivation

For years, brave Drupal community volunteers have been maintaining the Form API (FAPI) Reference, which is currently being displayed on api.drupal.org, and is part of the Documentation git repository. This lists all the form elements and all their properties, but it doesn't contain render elements, and it is VERY difficult to maintain (the file is hard to edit). It also suffers from being far from the Drupal Core code that it is documenting, so when elements and properties in Drupal Core are updated, the FAPI reference is usually not updated until someone notices it's out of date and files a separate issue.

[As a note, the issue to fix this problem was first reported in November 2006. The original issue was moved to the API project at some point (#100680: [meta] Make API module generate Form API documentation), and this issue was spun off to discuss the Drupal Core API documentation changes that would be needed to let the API module parse and display the resulting documentation. This issue summary now contains all the proposals from that previous issue and the following discussions here, as of October 19, 2015.]

Proposed resolution

Note: The specific proposal under consideration is to use essentially (f) for elements and (h) for properties. It may need slight refinements when we come down to the details of making a patch.

Requirements

The system we adopt for documenting form and render elements and their properties needs to have the following features:

1. Have the documentation of elements and properties be at a minimum in the Drupal Core code base, and ideally, very close to where they are defined. Elements are defined in hook_element_info() implementations, and properties are implicitly defined in theme templates and related functions that use them to format the output of the element.

2. The API module needs to be able to parse the documentation and make a list of elements and a list of properties, similar to the current FAPI reference (with cross-links between elements and properties, and maybe a table like at the top of the current FAPI reference). Ideally, on api.drupal.org, in a form/render array, the element names and property names would link to their documentation pages. And ideally, on an element or property page, there would be a list of "Functions that use this property/element" references.
Separate issue for that: #100680: [meta] Make API module generate Form API documentation

3. There are different types of elements:
- Form input elements
- Other form-related elements
- Render elements
We need to be able to document for a given element, which type it is.

4. Element documentation needs to include: machine name, type, one-line description, longer description (optional), example usage, @see links to examples and related theme/preprocess functions, which properties it uses and their default values.

5. There are different types of properties (some overlap):
- Internal properties.
- Properties that all render elements inherit automatically.
- Properties that all form input elements inherit automatically.
- Properties that are common to a subset of render elements (only want to document them once)
- Properties that are unique to one type of render element, or whose meaning is different from the usual for one type of render element.

6. Property documentation needs: #name, internal or not, automatically inherited or not, type (same as element types), one-line description, longer description (optional), some documentation of what the provided value needs to be, the default value (for automatically inherited properties), usage example, @see references to relevant preprocessing functions, theme functions, and examples.

Proposals for how to satisfy the requirements

a. Don't do this in core at all. Instead, move the Form API reference page into the Drupal Community Documentation on drupal.org so at least people can take a shot at editing it without a commit to the Documentation repository.
- Advantage: a slight bit better than current status quo.
- Disadvantage: page is still very hard to edit, and documentation still separated from code.

b. On Drupal.org, make little content types for documenting elements and properties, and use Views to make the reference page. These would have to have Drupal version tags on them somewhere.
- Advantage: at least it would be easier to edit.
- Disadvantage: documentation still very separated from the code.

c. Put the documentation into .info or .yml files (probably YML, which the API module already knows how to parse, and which is structured). Put these into the Core codebase (at least for Drupal 8).
- Advantage: easy to edit (familiar YML syntax), part of Core code base, parseable by API module.
- Disadvantage: Not very close to where the elements and properties are defined. [See also: alternative proposal g]

Sample of how this could look (I probably have the format wrong and the details screwed up, as I have totally just made this up; the original proposal from years back was for .info files, but I think we would now want to use YAML):

# system.element-doc.yml
radios:
  type: form_input
  summary: 'Set of radio buttons.'
  documentation: 'Longer description here.'
  example: comment_controls
  see_also:
    - radios.html.twig
  properties:
    - options
    - label
#system.property-doc.yml
options:
  property_name: '#options'
  automatic: false
  internal: false
  type: form_input
  summary: 'List of options for form elements with multiple choices'
  default: 'array()'
  value: 'A simple array of options, or an array whose keys are the internal names and whose values are the corresponded translated display values'
  example: comment_controls
  see_also:
    - radios.html.twig

Notes:
- type for elements/properties would be one of: form_input, form, render
- For properties, I think we need to have the ability for the YAML entry to have a different name from the actual #name of the property. This would allow us to define several entries for a property like '#size', which has different meanings for different render elements. The properties list in the element would refer to the entry name in the YML file, not the actual #property name. So for example, we might have a generic 'size' entry, which would be used for textfields, and a separate entry called select.size, which would be used for select lists.

d. Use YML files or dummy functions for properties (see proposal c or g). For elements, put the documentation inside the hook_element_info() functions in /** */ comments.
- Advantage: Gets the element documentation right where it is defined, and the property documentation at least in the code base. Uses familiar PHPdoc syntax for the elements, and familiar YML syntax for the properties. Easy to edit. Parseable by the API module (will need small modification to read /** */ comments inside hook_element_info() functions).
- Disadvantage: Having /** */ comments inside function bodies makes them difficult to comment out (however, we have a lot of these in Core in D8 already, like /** @var \Class\Being\Used\Here */ for IDE hints, so this argument is a bit weak). Property documentation is still separated. Elements and properties documented differently.

Sample of how this could look for elements (see proposal c for properties documentation):

 // inside system_element_info():

 /**
   * Text field form element.
   *
   * Corresponds to an HTML input element, with type="text".
   *
   * Put some information here about autocompletes.
   *
   * Usage example:
   *    @code ... @endcode
   *
   * @form_input_element
   *
   * @see ...
   */
  $types['textfield'] = array(
    '#input' => TRUE,
    '#size' => 60,
    '#maxlength' => 128,
    '#autocomplete_path' => FALSE,
    '#process' => array('ajax_process_form'),
    '#theme' => 'textfield',
    '#theme_wrappers' => array('form_element'),
  );

Presumably here, the properties could be parsed from the code itself?

e. Put documentation for render elements and/or properties into other existing headers, such as theme functions/templates.
- Advantage: Puts documentation closest to where code changes are likely to affect it.
- Disadvantage: Scatters this documentation around, hard to find and collect. Hard to figure out how to put the various parts of element/property documentation in so they are collected into the Element or Property documentation (see items 4 and 6 in the requirements -- there are a lot of needed pieces for documenting each element and property, so it's difficult to figure out how this could fit into a different function/file documentation header).

This proposal is not really viable.

f. For modules that provide more than one element, separate out their hook_element_info() into individual functions. Put the documentation for the element into that function documentation header. (Properties still documented in .yml files or dummy functions, see proposals c and g)
- Advantage: Keeps documentation with declaration. PHPDoc is familiar. Easy to edit. No /** */ within functions.
- Disadvantage: more functions added, but this is not a major problem.

Sample of how this might look:

// system_element_info():
$types['textfield'] = _system_element_textfield();

/**
 * Defines a text field form element.
 *
 * Corresponds to an HTML input element, with type="text".
 *
 * Put some information here about autocompletes.
 *
 * Usage example:
 *    @code ... @endcode
 *
 * @form_input_element textfield
 *
 * @see ...
 */
function _system_element_textfield() {
   return array(
    '#input' => TRUE,
    '#size' => 60,
    '#maxlength' => 128,
    '#autocomplete_path' => FALSE,
    '#process' => array('ajax_process_form'),
    '#theme' => 'textfield',
    '#theme_wrappers' => array('form_element'),
  );
}

I think in this case, like in proposal d, we would be able to figure out which properties were used by looking at the function body.

g. As an alternative to YML files (proposal c), document properties in individual dummy "function" headers in an api.php file. (Elements would be documented using one of the other proposals.)
- Advantage: Uses familiar PHPdoc style.
- Disadvantage: They aren't remotely similar to functions really, so this could be confusing.

How this could look:

// in system_properties.api.php

/**
 * List of options for form elements with multiple choices.
 *
 * @property_form_input
 * @property_automatic false
 * @property_internal false
 * @property_name #options
 * @property_value
 *   A simple array of options, or an array whose keys are the internal names and whose values
 *   are the corresponded translated display values.
 * @property_default array()
 * 
 * @see radios.html.twig
 * @see comment_controls()
 */
function property_options() {
   // This is a dummy function for property documentation.
}

(h) Same as proposal (g) but without the dummy functions -- we have @defgroup blocks that do not have dummy functions, so why not also property function blocks?

/**
 * @property #options List of options for form elements with multiple choices.
 *
 * @property_form_input
 * @property_automatic false
 * @property_internal false
 * @property_name #options
 * @property_value
 *   A simple array of options, or an array whose keys are the internal names and whose values
 *   are the corresponded translated display values.
 * @property_default array()
 * 
 * @see radios.html.twig
 * @see comment_controls()
 */

(i) Use the existing classes for Drupal 8, and don't fix up Drupal 7 or earlier versions. See comment #94 for details.

The main idea of this proposal is to let the API module make a Listing page (similar to Classes, Functions, etc.) for Elements, which it would gather from the @FormElement and @RenderElement annotations that are already in the element classes. We'd make sure each class has good documentation (which we should do anyway), including its properties, using existing documentation standards. And we'd document the common properties of render and form elements on existing topics.

This proposal is the simplest to implement in Core, and would actually probably require the fewest changes to the API module too.

Remaining tasks

A. Decide on and adopt a standard for documenting form and render elements and properties.
B. Make patches for Drupal 8.x and 7.x, to move the documentation currently in the FAPI reference document into the Drupal Core code.
C. Make the API module parse and display this documentation information (separate issue #100680: [meta] Make API module generate Form API documentation).

User interface changes

No Drupal UI changes.

API changes

No Drupal API changes.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jhodgdon’s picture

Status: Active » Needs review

Here is the first pass at a documentation standard (well, actually it's not anywhere near the first pass -- you can read the history on #100680: [meta] Make API module generate Form API documentation if you're interested).

Thoughts?

----

Documenting form/render elements and properties

Drupal's Form and Render APIs make use of elements (defined in modules' hook_element_info() implementations) and properties (array keys in form/render arrays starting with #).

Document an element foo by adding a few tags to the documentation header of its theme, process, or preprocess function. Example:

/**
 * Returns HTML for a select form element.
 *
 * @param $variables
 *   An associative array containing:
 *   - element: A form element array containing the properties of the element.
 *     @properties
 *        #title, #value, #options, #description, #extra, #multiple, #options.
 *     @property_specific #size
 *       The width of the select element.
 *
 * @ingroup themeable
 * @form_element select
 */
function theme_select($variables) { }

Notes:
- Use the @form_element or @render_element tag at the end of the documentation block to indicate which form/render element you are documenting.
- At an appropriate place that makes sense in the documentation (such as within $variables['element'] documentation, as in this example), use the @properties tag to list the standard properties that this element makes use of. Do not include properties that are common to all form or render elements (such as #pre-render or #disabled).
- For any properties that either have documentation that is different from the standard, or that are specific to this form/render element, use the @property_specific tag to document the meaning of that property on this element.
- Wrap all documentation to 80 characters and indent, similar to other documentation tags.

Document core Drupal properties that are common to form elements on the drupal_build_form() function (or its equivalent in earlier/later versions of Drupal). We make a distinction between "all" properties (such as #disabled) that are inherited by all form elements, and "some" properties, which have a common meaning but are only used on some form elements (as indicated by them appearing in the @properties tag in the form element documentation, see above). Do not include render properties that are also used in forms (such as #pre_render). Examples:

   ... Besides the common renderable array
 *  properties listed in drupal_render(), the following properties are common
 *  to all form elements:
 *    @form_property_all #disabled
 *      If TRUE, the form element is disabled (greyed out).
...
 *  The following properties are used by some (but not all) form elements:
 *    @form_property #description
 *      The translated description of the form element, typically displayed
 *      below the input field.
 *   @form_property #size
 *      The width of the form element.

Notes:
- "all" elements are documented with the @form_property_all tag, indicating they are inherited by all form elements.
- "some" properties are documented with the @form_property tag, which gives the default documentation for the property. If a form element uses this property, it can either include it in its @properties tag, or override its documentation by using a @property_specific tag (see example above).

Document core Drupal properties that are common to render elements on the drupal_render() function (or its equivalent in earlier/later versions of Drupal). We make a distinction between "all" properties (such as #pre-render) that are inherited by all render elements, and "some" properties, which have a common meaning but are only used on some render elements (as indicated by them appearing in the @properties tag in the form element documentation, see above). Examples:

... The following properties
 *  are common to all renderable arrays:
 *    @render_property_all #type
 *      The type of element to render, as defined in a hook_element_info()
 *      implementation. Default property values for this element type from
 *      hook_element_info() are added to the $elements array.
...
 *   The following properties are used by one or more types of renderable
 *   arrays, but not all types:
 *   @render_property #markup
 *      HTML markup for this element. If #type has not been set and #markup is
 *      present, #type will be set to 'markup'.

Notes:
- "all" elements are documented with the @render_property_all tag, indicating they are inherited by all form and render elements.
- "some" properties are documented with the @render_property tag, which gives the default documentation for the property. If a form or render element uses this property, it can either include it in its @properties tag, or override its documentation by using a @property_specific tag (see example above).

sun’s picture

Thanks for resurrecting this topic with a concrete proposal.

  1. Elements can be both form elements and render elements. I'm not sure whether we should attempt to make a difference in the first place. That is, because most form elements can be rendered as pure render elements outside of a form, too (or at least, if that's not possible for a certain element, then that is a bug).
  2. We should define the @properties directive at the "top-level" like any other phpDoc property. An custom inline property like @link or @code would require a corresponding @endproperties directive, and I wouldn't want to go there.
  3. For the individual property declarations (both global and local), I'd love it if we could borrow some more semantics of @param; e.g.:
     * @property array #options
     *   An associative array whose keys are (machine) name for the OPTION form
     *   elements and whose values are the respective localized option labels,
     *   properly escaped for HTML.
    
  4. The special @property_specific tag/directive seems superfluous to me; we should be able to design this in a way that allows the parser to figure out what the global "master" declaration is. Quite potentially, the separate @property_all directive is sufficient for that, since only being used on drupal_render() and drupal_build_form() or wherever.
  5. I'm not sure whether it is appropriate to document an element in its theme function. But alas, can't think of a better place right now.
jhodgdon’s picture

RE #2...

1. I believe we do need the difference. Processing is different for elements passed through drupal_*_form() functions vs. just drupal_render(), and form elements will not work correctly if they are just passed through drupal_render(), in my experience.

2. Not sure what you are talking about. You mean you don't want @properties within @param? If so, that makes some sense.

3. Good idea.

4. OK, maybe this can be unified... but we do (I think) want to have a way to say "Use these standard properties and then add these specific/overridden properties", and we don't want to list all the ones that apply to everything (the "all" vs. "some" standard properties). I think this proposal accomplishes this, but I think we could also do it with a tag called @property vs. @property_specific.

5. I can't either, which is why I suggest either the theme, process, or preprocess function. That is where the properties are really used, so I think that is the best place to document them (as close as possible to the code that uses them to get the best chance at maintenance).

Anyway... let's wait for a few more comments and I'll address these ideas with a new proposal.

jhodgdon’s picture

Oh, and one more thing regarding:

That is, because most form elements can be rendered as pure render elements outside of a form, too (or at least, if that's not possible for a certain element, then that is a bug).

I don't really think this is true... For instance, I tried recently to use a D7 fieldset in a render array (not in a form), and it totally failed to work (didn't render right, didn't open/close, etc.). drupal_render() does not do the same processing as drupal_get/build_form() -- the form elements are not properly processed or preprocessed. I think this is generally true for any complex form element (I tracked down the reason at the time but I'm not remembering right now)... but I'm sure we *do* need the distinction. Form elements are not meant to be used outside of forms in any case (for instance, it is probably not valid HTML to have an INPUT element outside a FORM anyway, is it?).

sun’s picture

re: #4: That's exactly what I meant, and #857124: Collapsible fieldsets and vertical tabs do not work without form_builder() (Form API) is a known issue (bug report) already :) All form elements should perfectly work outside of a Form API context (which actually means, without form_builder() processing). If that is not the case, then that's a bug. :)

However, you're right in that form_builder() & Co. adds the following to each element:

1) additional default properties
2) default values for properties
3) properties holding callback stacks

1+3 are Form API specific properties, such as #default_value, #value_callback, #tree, #parents, #array_parents, #process, #after_build, etc, which can easily be documented globally only, because they cannot be overridden either way.

2 is a bit more tricky, since that affects stuff like #attributes, #disabled, #readonly, and #value. Circling back into the above, all elements that are compatible with plain drupal_render() (which, again, should mean all form elements ;)) are using appropriate PHP conditions and control structures whenever evaluating those properties in order to account for the case when form_builder() did not set up any default property values (or even the property array key itself).

jhodgdon’s picture

Ah, I wasn't aware of that... So. Any other opinions -- should we make any distinction at all between form elements/properties and render elements/properties? It sounds like there *is* a distinction between form properties and render properties (those ones listed in #5 that the form builders add)... but maybe there is not a distinction between form/render elements (at least if that bug is fixed).

And I also remembered that in my last proposal on the other issue, I made a section for "internal" properties that the Form/Render API adds/uses (not meant to be set up in a form/render array or used in theme/preprocess/process functions). So this would be added to the render section of the proposal (and maybe the form section too):

 *   The following internal-use properties are common to all renderable arrays:
 *   @render_property_internal #printed
 *     During rendering, this function flags each element with a #printed
 *     status to indicate that the element and its children have already been
 *     rendered. If an already-rendered element is passed in, nothing is
 *     returned from this function.

Again, I think we do want to make a distinction between properties you should be using when defining form/render arrays, and ones that you shouldn't (but which you might see if you use print_r and wonder what they are for).

sun’s picture

TBH, a simple "Internal." as the first word in the property description sounds perfectly sufficient for that. For now, I'd rather go simple instead of trying to account for all possible edge-cases :)

jhodgdon’s picture

Taking (I hope) the comments above into consideration, here's a second pass at a standards proposal. A couple of notes pertaining to the comments above:
- We decided there was no distinction between form and render elements, so those have been combined.
- We decided there were some properties specifically used/added during form processing, so those are using a different tag.
- Added data types.
- Moved the documentation of elements/properties out of @param section.
- Changed @render_property_specific to just @render_property.
- Made three separate types of "common" properties: _all, _common, and _internal. I do think we want to have a distinction in the documentation between _all and _internal -- the _all properties are the ones that you would normally want to define in your form/render array, and the _internal ones are not generally defined when making a form/render array. So if we're building something like:
http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.ht...
from this documentation, I think we want to be able to list the standard properties, internal-use properties, and specific properties.

----

Documenting form/render elements and properties

Drupal's Form and Render APIs make use of elements (defined in modules' hook_element_info() implementations) and properties (array keys in form/render arrays starting with #).

Documenting elements

Document an element "foo" by adding a few tags to the documentation header of its theme, process, or preprocess function. Example:

/**
 * Returns HTML for a select form element.
 *
 * @param $variables
 *   An associative array containing:
 *   - element: A form element array containing the properties of the element.
 *
 * @render_element select
 * @render_properties
 *   #title, #value, #options, #description, #extra, #multiple, #options.
 * @render_property int #size
 *   The width of the select element.
 *
 * @ingroup themeable
 */
function theme_select($variables) { }

Notes:
- Use the @render_element tag near the end of the documentation block to indicate which element you are documenting (there is no real distinction between Form API and Render API elements).
- After the @render_element tag, use the @render_properties tag to list which optional standard form/element properties this element makes use of (if any). Do not include render_property_all or render_property_internal properties (see below).
- For any properties that either have documentation that is different from the standard, or that are specific to this form/render element, use the @render_property tag to document the specific meaning of that property on this element. Give the data type of the property (see the @param/@array data types section for details), the name of the property, and a description.

Documenting Render API properties

Document core Drupal properties that are common to render elements on the drupal_render() function (or its equivalent in earlier/later versions of Drupal). Some of these properties are common to all render elements (either they are added to all elements by drupal_render() or another function, or all elements need to define them). Others are used by several, but not all, elements, and have a common meaning for elements where they are used. Element documentation (see above) should omit the common-to-all properties entirely, and should use the @properties tag to indicate which common-to-some properties pertain to this element. Examples of render API property documentation on drupal_render():

 * The following properties are common to all renderable arrays:
 *   @render_property_all string #type
 *     The type of element to render, as defined in a hook_element_info()
 *     implementation. Default property values for this element type from
 *     hook_element_info() are added to the $elements array.
...
 * The following properties are common to some renderable arrays:
 *   @render_property_common string #markup
 *     HTML markup for this element. If #type has not been set and #markup is
 *     present, #type will be set to 'markup'.
...
 * The following properties are used internally by the Render API:
 *   @render_property_internal bool #printed
 *      Set to TRUE to indicate that a section of the render array has already been processed.
...

Notes:
- Common-to-all properties are documented with the @render_property_all tag, indicating they are inherited by all form and render elements. Form/render elements should not list these properties.
- Common-to-some properties are documented with the @render_property_common tag, which gives the default documentation for the property. If a form or render element uses this property, it can either include it in its @render_properties tag, or override its documentation by using a @render_property tag (see example above).
- Internal-use properties are documented with the @render_property_internal tag. Form/render elements should not list these properties.
- When documenting a property, give the data type of the property (see the @param/@array data types section for details), the name of the property, and a description.

Documenting form properties

Some properties are added to form elements during form processing with drupal_build_form() and related functions, or are used during form processing, but are not added/used in the basic render API. These should be documented in a manner similar to the render properties (see section above) on the drupal_build_form() function, along with common-to-some properties that are only used by form elements. Examples:

 * Besides the common render array properties listed in drupal_render(), the following
 * properties are common to all form elements:
 *   @form_property_all bool #disabled
 *     If TRUE, the form element is disabled (greyed out).
...
 * The following properties are used by some (but not all) form elements:
 *   @form_property_common string #description
 *     The translated description of the form element, typically displayed
 *     below the input field.
 *   @form_property_common int #size
 *     The width of the form element.
 ...
 * The following properties are used internally during form processing:
 *   @form_property_internal string #id
 *     The HTML ID assigned to the form field for this element.

Notes:
- Common-to-all properties for form processing (if they aren't also used during generic render processing) are documented with the @form_property_all tag, indicating they are inherited by all render elements that undergo form processing. Form elements should not list these properties.
- Common-to-some properties that are meant for form elements are documented with the @form_property_common tag, which gives the default documentation for the property. If a form element uses this property, it can either include it in its @render_properties tag, or override its documentation by using a @render_property tag (see example above).
- Internal-use properties specific to form processing are documented with the @form_property_internal tag. Form elements should not list these properties.
- When documenting a property, give the data type of the property (see the @param/@array data types section for details), the name of the property, and a description.
---

jn2’s picture

#5 still leaves me with a question.

If there is no distinction made between form and render elements in the doc headers, then those default properties added by form_builder() will not be listed or linked to form elements in this reference. If it's documented globally somewhere, how do you show which elements they apply to? A simple list?

Also, just because a property cannot be overridden doesn't mean it might not be of use in some situations. (In which case people would want to know about it.)

I completely agree that form and render elements should all be included in one reference. I just wonder how to show that some elements can have access to the form_builder default properties. Seems that might be important in the reference doc that will be put together from these headers.

Edited: I'm making the assumption that the elements referred to in #5 are only form elements and that simple render elements are not affected this way by form_builder() and co. even when used in a form.

jhodgdon’s picture

RE #9... a few thoughts that may clarify this:

a) When we add a document header for a form/render element, the doc header is only going to list the properties that are specific to that element, or that have special meanings for that element, not any of the default properties that are common to all form elements or all form/render elements (#theme, #pre_render, etc.). We don't want to get into a situation where every element has to list these, or even encourage it, because down the road, some default form/render element property will be added/removed and we'd have to go through all of the elements and edit their documentation blocks. That is not easy to maintain, as anyone who has tried to maintain the current FAPI document knows, I'm sure!

b) From #9:

...just because a property cannot be overridden doesn't mean it might not be of use in some situations. (In which case people would want to know about it.)

I totally agree, but at the same time, see (a). Keep in mind that on api.drupal.org, we can do anything we want for listing and cross-referencing (and I do think we want to list all properties, all elements, and cross-reference them) -- but we should discuss the specifics of the api.drupal.org output on #100680: [meta] Make API module generate Form API documentation, not here.

c) I still think that the information in the doc headers in the proposed standards will be enough to do any cross-referencing and listings that we would want to do (including generating something very much like the FAPI reference). I could be wrong, though, so if you can think of some additional information that we need to include, let's make sure it gets added to the standard.

d) From #9:

I just wonder how to show that some elements can have access to the form_builder default properties.... I'm making the assumption that the elements referred to in #5 are only form elements and that simple render elements are not affected this way by form_builder() and co. even when used in a form.

My read of sun's comments above is that this is incorrect, and if you look at form_builder(), it is definitely doing the same thing with each array element in the form, independent of what type of element it is, right? I don't see anywhere in there where it says "If this is an ordinary render element, skip these steps and just render it with drupal_render()". It does do something extra with elements that have the #input property set to TRUE... and maybe we need to make another property distinction for properties that are specific to form input elements (anything used/output by _form_builder_handle_input_element()), and maybe we do need to mark some elements as being form *input* elements? Hmmm.

jhodgdon’s picture

So... There are probably three things we need to add to this standard:

1. Some way to indicate a function or functions where the element (and property?) is used (an example usage).

2. Some way to indicate that a particular element is a form input element, since these are handled specially in form_builder().

3. Some way to indicate that a property is specific to form input elements.

jhodgdon’s picture

Regarding the way to indicate that something is a form input element... maybe the place we should document elements is inside the hook_element_info() implementation and not in the theme/preprocess function? Then we could pull the element definition array out to display it as the source code, which would also tell us what the default values for the properties are (including the #input = TRUE on the input elements).

That would also avoid the problem I've been ruminating on, of separating out the element documentation from the theme function documentation, because it would be totally separate.

jn2’s picture

Re: #10 a)
Yes, I understand that the default properties should not be included in the doc block. Actually, that is the point. If all form elements share certain default properties, as I have so often heard in the past, then there should be some simple way to mark them so that these properties can be included in the parsed reference. But I think you have hit on the differentiator: the #input property. So that answers my concerns.

Re: #11 1.
We had discussed including some kind of automatic listing of functions that use elements, similar to the listings included for hook implementations in the API reference. (Such as "The following functions use :") I assumed that could be handled by #100680: [meta] Make API module generate Form API documentation and didn't need to be included in the doc block.

Re: #12
I've also been wondering how to resolve the difference between the element documentation in the FAPI reference and the theme function documentation.

jhodgdon’s picture

RE #11/1 => You are correct -- I think that we can automatically generate the list of "functions that use this element". If we also move the documentation into the hook_element_info() so it is separate from the theme function, then we can also use @see in those docblocks if we want to. I think this has a lot of advantages... OK, it's time for a new standard proposal:
----

Documenting form/render elements and properties

Drupal's Form and Render APIs make use of elements (defined in modules' hook_element_info() implementations) and properties (array keys in form/render arrays starting with #).

Documenting elements

Document an element "foo" by adding a documentation header to the definition of the element in a hook_element_info() implementation. Example:

// Inside system_element_info():
  /**
    * Form input element for a select list.
    *
    * Optional longer description would go here.
    *
    * @input_element select
    * @render_properties
    *   #title, #value, #options, #description, #extra, #multiple, #options.
    * @render_property int #size
    *   The width of the select element.
    *
    * @see function_that_uses_this_element()
    * @see theme_select()
    */
  $types['select'] = array(
    '#input' => TRUE,
    '#multiple' => FALSE,
    '#process' => array('form_process_select', 'ajax_process_form'),
    '#theme' => 'select',
    '#theme_wrappers' => array('form_element'),
  );

Notes:
- The first line should either start with "Form input element for" or "Render element for", and should describe the purpose of the element.
- An optional longer description can also be included, after a blank line (similar to function documentation).
- After the descriptive lines, use either a @input_element (for form input elements only) or @render_element (for all other elements) tag, giving the machine name of the element you are documenting.
- After the @input_element/@render_element tag, use the @render_properties tag to list which optional standard form/element properties this element makes use of (if any). Do not include *_all, *_input, or *_internal properties (see below).
- For any properties that either have documentation that is different from the standard, or that are specific to this form/render element, use the @render_property tag to document the specific meaning of that property on this element. Give the data type of the property (see the @param/@return data types section for details), the name of the property, and a description.
- You can also use @see tags at the end of the documentation block, to point people to functions with especially good examples of usage of elements, to theme and processing functions that might need to be overridden, etc.

Documenting Render API properties

Document core Drupal properties that are common to render elements on the drupal_render() function (or its equivalent in earlier/later versions of Drupal). Some of these properties are common to all render elements (either they are added to all elements by drupal_render() or another function, or all elements need to define them). Others are used by several, but not all, elements, and have a common meaning for elements where they are used. Element documentation (see above) should omit the common-to-all properties entirely, and should use the @properties tag to indicate which common-to-some properties pertain to this element. Examples of render API property documentation on drupal_render():

 * The following properties are common to all renderable arrays:
 *   @render_property_all string #type
 *     The type of element to render, as defined in a hook_element_info()
 *     implementation. Default property values for this element type from
 *     hook_element_info() are added to the $elements array.
...
 * The following properties are common to some renderable arrays:
 *   @render_property_common string #markup
 *     HTML markup for this element. If #type has not been set and #markup is
 *     present, #type will be set to 'markup'.
...
 * The following properties are used internally by the Render API:
 *   @render_property_internal bool #printed
 *      Set to TRUE to indicate that a section of the render array has already been processed.
...

Notes:
- Common-to-all properties are documented with the @render_property_all tag, indicating they are inherited by all form and render elements. Form/render elements should not list these properties.
- Common-to-some properties are documented with the @render_property_common tag, which gives the default documentation for the property. If a form or render element uses this property, it can either include it in its @render_properties tag, or override its documentation by using a @render_property tag (see example above).
- Internal-use properties are documented with the @render_property_internal tag. Form/render elements should not list these properties.
- When documenting a property, give the data type of the property (see the @param/@array data types section for details), the name of the property, and a description.

Documenting form properties

Some properties are added to form elements during form processing with drupal_build_form() and related functions, or are used during form processing, but are not added/used in the basic render API. These should be documented in a manner similar to the render properties (see section above) on the drupal_build_form() function, along with common-to-some properties that are only used by form elements. Examples:

 * Besides the common render array properties listed in drupal_render(), the following
 * properties are common to all form elements:
 *   @form_property_all bool #input
 *     If TRUE, this is an element for form input. If FALSE or omitted, this is a generic form/render element.
...
 * The following properties are used by all form input elements (form elements that take input):
 *   @form_property_input bool #disabled
 *     If TRUE, the form element is disabled (greyed out).
...   
 * The following properties are used by some (but not all) form elements:
 *   @form_property_common string #description
 *     The translated description of the form element, typically displayed
 *     below the input field.
 *   @form_property_common int #size
 *     The width of the form element.
 ...
 * The following properties are used internally during form processing:
 *   @form_property_internal string #id
 *     The HTML ID assigned to the form field for this element.

Notes:
- Common-to-all properties for form processing (if they aren't also used during generic render processing) are documented with the @form_property_all tag, indicating they are inherited by all render elements that undergo form processing. Form elements should not list these properties.
- Properties that are used by all form input elements are documented with the @form_property_input tag.
- Common-to-some properties that are meant for form elements are documented with the @form_property_common tag, which gives the default documentation for the property. If a form element uses this property, it can either include it in its @render_properties tag, or override its documentation by using a @render_property tag (see example above).
- Internal-use properties specific to form processing are documented with the @form_property_internal tag. Form elements should not list these properties.
- When documenting a property, give the data type of the property (see the @param/@array data types section for details), the name of the property, and a description.
---

jn2’s picture

Status: Needs review » Reviewed & tested by the community

Re #14

The more I think about it, the more I like putting these doc blocks in hook_element_info(). A big +1 on that!

The standard is excellent! A couple of minor changes, listed below, might improve the examples. Assuming those changes can be made for the actual listing, I'm tentatively setting this to RTBC.

Changes for examples:
In the actual text used for the standard, the definition of #size should read:

Size of the select box in lines.

What's included above is the default meaning for textboxes etc.

The @render_properties would be better represented by:

#default_value, #empty_option, #empty_value, #multiple, #options, #size,  #title, #type
jhodgdon’s picture

#15 - Thanks for those corrections! Let's see if anyone has any other comments on the proposed standard ==> the proposal is now "#14 with the example corrections from #15"

jhodgdon’s picture

One more addition to the standard: We should define a @defgroup render_elements (or something like that, to give an overview of what render elements and properties are), and make sure that every element has @ingroup (group_name) in it.

jhodgdon’s picture

So.... Does anyone besides jn2 and myself want to comment on this standard before we officially adopt it?

sun’s picture

  1. We cannot use the multi-line comment syntax within the function body. I'm not sure whether our coding standards officially state already that this is not allowed, but if not, I totally think they should. I've never seen any solid/clean code anywhere (not limited to PHP) that would use the multi-line comment syntax for inline comments within functional code (the only exception to that is CSS, but the CSS spec has no notion of inline comments in the first place).

    To overcome this issue, we can move the element declarations into individual functions and call them from within the respective hook_element_info() implementation. I'm fairly sure that these element declarations will be converted into some better plugin-alike code at some point anyway, so doing this would not conflict with that at all. The additional function calls will not be measurable, since element_info() is statically cached.

  2. Even though your analysis for distinguishing between form elements and input elements is correct, the "@input_element" directive looks and sounds a bit strange to me. Primarily, because "input" cannot be immediately associated with any particular subsystem by anyone. The differentiation between input and render elements is correct, but I'd highly recommend to keep @form_element as the directive, so the relationship to Form API is clear.
  3. The @render_properties directive was technically only correct in the previous idea of documenting the elements on the theme functions. That is, because the definition does not know what properties are actually used by the rendering/theme process. If the idea is to denote which properties are prepared for possible render/theme consumption (without knowing which will be used), then this makes more sense. But it was/is not 100% clear to me after reading the proposal.
jhodgdon’s picture

RE #19 -

1. Why not? The API module can definitely parse this without any trouble, and putting the comments within the hook_element_info() will ensure that the documentation is with the code, which is always good. Regarding this being non-standard for documentation in general, standard JSDoc definitely uses this type of thing (/** comments within function bodies and {} closures).

2. How about @form_input_element then? The point is, it's only elements that have #input => TRUE when used in forms.

3. The idea is only to document properties that are specifically used in this element's default process/pre-process functions. Sure, themes and processing can be overridden, but we've always documented the default behavior in the FAPI reference... Don't you agree that is the right thing to do? We can/should put wording in the standard saying you are documenting the default behavior.

sun’s picture

Fine with 2) + 3). :)

However, I still wholeheartedly disagree with 1) — putting phpDoc block comments including phpDoc syntax and directives within function bodies is just simply wrong from my perspective. Even if there were no phpDoc directives involved, it would still be a T_DOC_COMMENT within a function body, and we're not using the multi-line comment syntax within function bodies, nor do I know of any other PHP-based project having clean code that allows or uses them in function bodies, and I do not want to open the door for allowing them in our code base, even if it was an exception for hook_element_info() only. Within function bodies, we're only using // Inline comments.

But as already mentioned in #19, there's a very simple and straightforward way around that issue:

function system_element_info() {
  $types['textfield'] = system_element_info_textfield();
}

/**
 * Defines #type textfield.
 *
 * @form_input_element textfield
 * ...
 */
function system_element_info_textfield() {
  return array(
    ...
  );
}

And, as also mentioned before, there's a very high chance that element type definitions will be "plugin-ified" either way in the foreseeable future, which will most likely turn them into element type classes, so splitting them here for the purpose of being able to properly document them does not hurt or conflict with that at all. We don't want to hold off this API docs improvement on those potential future changes, so just simply splitting the definitions into separate callbacks is perfectly fine. The results of hook_element_info() are statically cached, so the additional function calls also do not present a problem.

jhodgdon’s picture

Status: Reviewed & tested by the community » Needs review

Let's see if we can get some other core developers to weigh in on the argument in #21. I doubt we would adopt it for D7 (and I would *really* like to get this documentation incorporated into D7 if possible)... and it sounds like it's kind of an interim solution for D8, right? How about adopting the interim solution of putting the docs into hook_element_info() instead? :)

sun’s picture

I can't see a reason why #21 couldn't be done for D7 as well. There's no API change involved. The separate functions are only called internally from system_element_info() - the returned result is exactly the same.

jhodgdon’s picture

*could* - yes. *would* - ? And does it really make sense to change the coding style for all hook_element_info() implementations just for a documentation standard? It seems relatively extreme, and I still don't see why having /** */ comments within a function is so horrible/wrong/evil/whatever.

As another note, this coding style change would need to be made in 6 core functions:
http://api.drupal.org/api/drupal/modules!system!system.api.php/function/...
(not just system_element_info()). And any contrib modules that wanted to comply with the new standards.

tstoeckler’s picture

I would actually consider #21 to be a DX improvement regardless of the Docs implications.
Example: You want to find out the default #size of textfields. As a core dev you know that system_element_info() is your friend, but if you're not, you'll probably end up searching for "textfield" on api.drupal.org, which doesn't get you anywhere. Seeing a function called "system_element_info_textfield" or similar on that list, would definitely help.
I have actually wanted to open an issue for that before, but never came around to it.


So +1 for #21 from me.
Just a note: If we do this, we should update the docs for hook_element_info() to recommend this practice.

jhodgdon’s picture

RE #25 - if we get elements onto api.d.o (which is most of the point of this issue anyway), you will be able to search for them on api.drupal.org, with or without there being a function with that in the name. So moving them to additional functions will not really help the developer experience on api.drupal.org.

tstoeckler’s picture

Re #26: Oh, I didn't realize that. That's sweet!

Still +1 for #21 from me, but now solely because it seems to be the simplest and most sensible resolution. Like @sun I also really dislike PHPDoc inside of function bodies.

effulgentsia’s picture

I still don't see why having /** */ comments within a function is so horrible

I don't know if it's horrible, but it makes debugging frustrating, because you then can't bulk comment out code. Note that it's already frustrating that you can't bulk comment out multiple functions at a time, but expanding that to being granular within a function would make it worse.

As another note, this coding style change would need to be made in 6 core functions

Would it? Any reason not to support a coding style of "only break up your hook_element_info() implementation if you're defining more than 1 element type"? Only system_element_info() does that.

jhodgdon’s picture

RE #28 - I see your point (although I am not sure how often someone needs to comment out pieces of system_element_info() to debug). So... As I see it, we have three options for where to place the property/element documentation:

a) Put the docs for elements within function doc blocks (either theme functions as was proposed in #1 and other proposals above, hook_element_info() implementation function headers, or dedicated "generate this element" functions). The problem with this (the reason the proposal changed to putting element docs inside system_element_info() in the first place) is that if you want to use @see, @code, etc. and have multi-paragraph docs for the elements (and I think we need to), it's really not possible to tell which paragraphs or sections of doc belong to the element and which belong to the function. [We incidentally would have the same problem with the property documentation, but have (somewhat tacitly) decided that a one-paragraph description of each property is sufficient -- if it isn't, we need to rethink the idea of putting the property docs within other doc blocks too (drupal_render(), drupal_build_form() and individual element blocks).] I really don't think this is a feasible option, the more I think about it.

b) Make individual doc blocks for the elements, and locate them where the elements are defined (inside the code for hook_element_info() implementations) [the latest proposal, #14/#15, does this]. This has problems outlined nicely in #28.

c) Put the element (and possibly the property) documentation into new .api.php files. This way they could each be their own doc blocks [avoiding the problems of (a)] and we would also avoid the problems of (b). The disadvantage here is that like hook docs, having the documentation separate from where the elements/hooks are actually defined or used in code means that hooks/elements can easily be added/changed without the docs being updated. (For instance, somewhere in the D7 dev cycle, I searched for where hooks were being invoked, and found about 30 that were completely undocumented, and we have issues all the time about hooks whose documentation hasn't kept up with the code.)

I can't think of any other options... and I don't think any of the three options is ideal -- they each have advantages and disadvantages. My feeling is that (b) [the current proposal in #14/#15] is the best option. But I would be willing to go with (c) if we have to -- I'm not excited by the idea, because I already think maintaining the hook docs is problematic, but willing. :)

Thoughts?

sun’s picture

I don't really understand the resistance to #21. It's the most logical thing to do, since the actual underlying goal is to treat each of the element types as their own thing. So let's turn them into own things. :) There's nothing in our coding standards or coding style that would require anyone to "Define element types within hook_element_info(), you MUST NOT call any other functions to define your element types." and alas, I would strongly object and won't fix such a proposal. It also keeps the docs where they belong and not in a separate place.

Lastly, the longer we wait with this, the higher is the chance that an OOP-ified re-architecture will take over the decision at some point. Essentially that would (or possibly will) boil down to something along the lines of $form->addElement('textfield')->set..., whereas addElement() instantiates a new Drupal\system\Form\Text plugin, and its properties, methods, and behavior is documented right on that very plugin class.

Therefore, I see the approach of splitting the element definitions into separate functions as a step that hints at that future progression. Even if it happens for the purpose of documentation only. That is because, if we didn't have the documentation issue for form/render elements, then we likely also wouldn't have most of the other architectural issues with Form/Render API. For many people, it's exactly the documentation and understanding issue that is one of the main reasons for even thinking about revamping Form/Render API in the first place.

But anyway - possible future aside, the only counter-argument against #21 was that it would directly imply some kind of new coding standard that everyone is required to follow, regardless of whether there's any need for it. But that's not the case - you can follow this style in order to document your element type definitions. Whether you want and do is left for you to decide. Only Drupal core would lead by example, both in D8 and D7.

jhodgdon’s picture

Resistance to #21 -- see comment #29 (a). I just don't see, as a practical matter (as the API module maintainer), how to disentangle the element docs from the function docs, if we put element docs inside a function doc-block. So I don't want to put element docs in function doc-blocks, whether they're hook_element_info() or special-purpose functions.

jhodgdon’s picture

So... I believe we have pretty much agreed on standards for how to document the properties and elements. We just need to settle the question of where to put the element documentation.

I just updated the issue summary with what I think are the latest ideas that we all agree upon for property and element documentation (http://drupal.org/node/1617948#summary-proposed-resolution). Please check those over and see if I've messed anything up, or if we need to add anything there.

I also updated the issue summary with a list of ideas for where to put the element documentation, and the advantages and disadvantages of each idea (http://drupal.org/node/1617948#open-question). What should we do on this?

My current opinion: I'm becoming more and more inclined to put the element documentation in api.php file(s), given that sun and effulgentsia are so opposed to putting it inside the system_element_info() function body (and I understand their reasons), and that as API module maintainer, I'm opposed to putting it inside of any function documentation block (because it's not clear to me how to separate out the parts of the block that are function docs vs. element docs). Having the elements in a separate api.php file is probably the only way to overcome both of these objections. And since we also probably want to have a @defgroup to give an introduction to form/render API, putting it all together in system.elements.api.php or something like that seems like it might make the most sense.

Thoughts? Can we all get behind this compromise idea of api.php files for the place to put the element docs, and go forward to (a) a patch and (b) some new API module code? :)

sun’s picture

The missing connection that I presume but you don't seem to want to make is: function == element

Thus, the "problem of having to figure out how to separate the function docs from the element docs" does not even exist in my book. The function is the element.

I can only refer once again to what I've said earlier - the moment these element definitions will turn into classes (and I'm confident that this will happen at some point), the class will be the element. So above equation is only changed into: class == element

Essentially, the additional directives are only tacked onto the function, so as to be able to reference them more easily. In other words, the only effect of @form_input_element select is that it acts as an alias for system_element_info_select(), so that other code parsing is able to look up and cross-reference the function whenever determining "select" in a certain fashion.

In my mind, that's just KISS.

Before detaching element type definition docs from their actual code definitions (into .api.php), I'd rather defer this entirely on future OO conversions, since that would be a pain to maintain.

jhodgdon’s picture

RE #33 - Agreed, that is precisely the problem -- I don't agree with you that the function *is* the element, even if we follow the suggestion in #21. The function needs to be documented as a function (http://drupal.org/node/1354#functions), and the element needs to be documented as an element (see issue summary above). How are they the same thing, even if the sole purpose of the function is to generate the element (even that language gives it away -- the element is definitely a concept separate from the function)?

And having an element be an alias of a function doesn't make sense to me either, in the context of the API module. We don't, for example, want the "@ingroup elements" to apply to the function -- we want the *element* to be part of that group.

Regarding deferring until some OO conversion is done... ideally, the solution we choose would work for both Drupal 7 and Drupal 8. In which case, I find the idea of putting the element documentation into an api.php file even more compelling. If elements turn out eventually to be handled by plugin classes, then it becomes even more apparent that they're different things (to me, anyway), since classes have member variables, member functions, inheritance, etc. -- none of which apply to "elements" in the abstract sense. I definitely wouldn't want their documentation to be merged.

sun’s picture

Assigned: Unassigned » webchick

I doesn't look like we're able to come to an agreement. ;) Therefore, delegating and deferring to @webchick (who cares for such details, too) for mediation and/or making a final call. :)

jhodgdon’s picture

That sounds like a good idea.

Note to webchick: the issue summary is updated as of comment #31. I suggest you read the issue summary and then comments #32-35 to see what you are being asked to mediate. Thanks!

nevergone’s picture

What would there be need for in order for the solution of the issue to go on? Drupal 7 port is coming soon?

jhodgdon’s picture

We asked webchick to comment and we're waiting for her to do so. Otherwise, we are apparently at an impasse.

Gábor Hojtsy’s picture

Hit the same problems when documenting the new langugae_select element with @LoMo at #1739876: Document new language_select field type.

jhodgdon’s picture

Yes it would *definitely* be good to get this resolved... but as noted above we have come to an impasse for the moment and are waiting for hopefully webchick or dries to weigh in.

webchick’s picture

Coming back from DrupalCon, I have a backlog of over 60 RTBC issues, including some critical and major bugs/tasks that unblock work in numerous other areas. I am therefore not currently planning on prioritizing this issue anytime soon. If this is the wrong course of action, please explain why and I'll try and make time for it.

effulgentsia’s picture

FileSize
17.94 KB

I asked jhodgdon in IRC what her objection to #21 is, and she pointed me to #29a and #34. Seems like it basically boils down to the question of whether a MODULE_element_info() or MODULE_element_info_ELEMENT() function ever needs to have a documentation identity distinct from the element. I don't think that it does, but maybe I'm missing something?

Here's a patch to demonstrate my interpretation of #21 and why I don't see a difference between the function and the element. Perhaps someone can add to this an example where the difference would need to come into play?

Also, I doubt that we'll be converting element types to plugins in D8 (there's many other systems that I would consider a better fit to spend time converting, and in D9, we may want to evaluate a move to a Symfony Forms based API), and I see no reason we can't backport this patch to D7, so I think it makes sense to proceed with this, or with one of the other alternatives mentioned in the issue summary.

effulgentsia’s picture

[double post with #42]

jhodgdon’s picture

You've nicely illustrated my point with this patch. Take this example:

/**
  * Implements hook_element_info().
+ *
+ * @render_element field_ui_table
  */
 function field_ui_element_info() {

field_ui_element_info() is a function. It's an implementation of hook_element_info(), and will be listed in the "implementations of hook_element_info()" page on api.drupal.org, as well as in the "Functions" section of the field_ui.module page. So yes, it *is* a function, and it needs to have that first line to comply with our standard for hook implementations.

And what you've added to this would make it also be the render element documentation for the "field_ui_table" element, which would need to have a *lot* of other information, like this example from the issue summary:

/**
    * Form input element for a select list.
    *
    * Optional longer description would go here.
    *
    * @form_input_element select
    * @render_properties
    *   #empty_option, #empty_value, #multiple, #options
    * @render_property int #size
    *   The number of lines in a listbox-style select element.
    *
    * @see function_that_uses_this_element()
    * @see theme_select()
    * @ingroup elements
    */

I just don't see how to merge what we need for the function doc with what we need for the render element doc -- for instance if you have an @see or an @ingroup, which do they apply to, the function or the element doc? So my conclusion is that they need to be separate and we should probably just put both render element and render property documentation in separate api.php files, which just contain a bunch of documentation blocks like the one here, one after the other, with no code on them (and the API module will be quite happy with that).

sun’s picture

I really really like the patch in #42 :) Simplicity++

effulgentsia’s picture

for instance if you have an @see or an @ingroup, which do they apply to, the function or the element doc?

Is there a reason why "both" is not a good answer? If I found this doc by perusing the "Functions" section of the field_ui.module page, I'd want to follow the @see links. If I found this doc by perusing render elements, I'd want to follow the @see links.

jhodgdon’s picture

Status: Needs review » Needs work

Regarding the patch in #42 -- it is nice and clean, at least in part, because it does not have anywhere near all the necessary documentation for form/render elements. I invite you to flesh out a couple of the items in the patch with all of the documentation for an element (see #14 for what documentation needs to be included) and demonstrate how it all fits together with the function docs, given that they need to have different summary lines, etc. I'm skeptical that it makes sense, but possibly willing to be convinced by an actual patch that includes all the necessary documentation for a couple of elements. I would like to see one example that goes into one of the newly created functions, and another example that goes into a hook_element_info() that isn't being broken up.

I would also like to see a D7 maintainer comment that they would be willing to commit a patch like #42 (but with a lot of added docs), since it does change the code and not just documentation.

webchick’s picture

Assigned: webchick » David_Rothstein

For that question, we'd be better off to ask David, as the D7 release manager. Re-assigning to him for a moment.

David_Rothstein’s picture

Assigned: David_Rothstein » webchick

From the point of view of backportability, I don't see any problem with #42. Adding new functions in the system_* namespace isn't really a problem for Drupal 7.

Personally (i.e., not commenting as D7 maintainer anymore), I have to say that from the point of view of someone implementing hook_element_info_alter() I wouldn't be a huge fan of that change, because you go from simply having the array you want to alter right there in one place in the code to something that looks more complicated to read and understand... But otherwise I don't have a strong opinion.

Probably, my vote would just be to use something like the *.api.php idea. It's simpler than any of the other ideas, and also has the advantage that it's a nice file to read through (even when you're not on api.drupal.org) where you can learn about the core render API all in one convenient place. The main objection to it seems to be that it will be harder to keep the documentation up to date, but I wonder how true that actually is. I see patches all the time that fail to update documentation correctly regardless of where it's located (even sometimes where the documentation that would need to be changed is visible in the patch context! - #1304486-9: Completely remove the ability to limit the number of shortcuts per set and http://drupal.org/node/1358140#comment-6320784 being an example of that which I just came across). So ultimately, it's up to patch reviewers to make sure that documentation gets updated when it needs to be, regardless of where in the codebase it lives.

And now, back to @webchick... :)

a.ross’s picture

Hm, this is a tricky matter. I think it would be more appropriate for Drupal 8 to do something along the lines of #42, however I have my doubts for D7, for a number of reasons.

D8 is scheduled to release in, what, Q4 2013? Is this issue high priority enough to justify possible practical issues with a backport? For example, a number of high usage modules implement this hook: hook_element_info implementations
For consistency, it's not nice that a module implements this hook (and documentation) differently from core. And maintainers may be unwilling to comply with core on this one. This might be a minor issue, but still.

So why not just live with the old documentation for D7, until - hopefully sooner than later - D8 is released? That would give us enough time to solve or minimize any issues that have or have not been overlooked.

Just my $0.03 ;)

nevergone’s picture

And now…? :S

nevergone’s picture

So that's it?

jhodgdon’s picture

Well, it's probably time to revive this issue.

Would someone who likes the idea of #42 like to expand the patch with all the necessary documentation that a render element would actually need (see comment #47)?

Or should we go with an elements.api.php file, as advocated on other comments?

jhodgdon’s picture

I have a new idea for this issue, which would involve zero code change from how we are currently doing things, and would only add inline ( // ) comments.

Here's a patch that illustrates the type of comments we'd add to system_element_info().

The idea:
a) Any hook_element_info() implementation with this type of documentation would have @element_list added to its doc block. This would clue the API module that it needs to do some special custom parsing. I could probably detect this from the function name, but I'd prefer to just have this tag (hook names tend to change over time -- I think this was hook_elements in the past wasn't it?), and it's only one line to add.

b) Within a function with the @element_list tag, // comments starting with @element or @property would get parsed for the form/render API reference.

c) Each documented element would need one of the following in the first line of its doc header:
- @element - if it is a render element
- @element_form - if it is a form-specific element (a render element that only works properly if it's inside a form)
- @element_form_input - if it is specifically a form element that takes user input
This would be followed by the name of the element (I could probably parse it out but I think it's easier if it's just provided). And then the next lines, indented two spaces, would describe it.

d) Each property would only be documented once. In one chosen occurrence of the property, we'd use one of the following:
- @property - if it is a property that is used on one or more elements but doesn't automatically apply to all
- @property_all - if it is a property that automatically applies to all elements
- @property_internal - if it is a property that is used internally by the render system
- @property_form_input_all - if it is a property that automatically applies to all elements declared as @element_form_input
- @property_form_input_internal - if it is a property that is use internally by the form/render system, but only applies to form input elements
This would be followed by the type and name of the property. And then the next lines, indented two spaces, would describe it.

I think this would be enough information to generate something pretty much like the Form API reference. Thoughts?

joachim’s picture

+++ b/core/modules/system/system.module
@@ -289,12 +305,27 @@ function system_element_info() {
+    // @property string #name
+    //   The name attribute of the button.
     '#name' => 'op',

I like the way this puts the description of each array property right next to the property itself.

Why do you need to repeat #name though? It's just below as the key of the array element.

Also, hook_element_info() only defines default values for form element element properties. If an element may have a property, but doesn't define a default, then it won't be in that hooks. Eg:

  // Input elements.
  $types['submit'] = array(
    '#input' => TRUE,
    '#name' => 'op',
    '#button_type' => 'submit',
    '#executes_submit_callback' => TRUE,
    '#limit_validation_errors' => FALSE,
    '#process' => array('ajax_process_form'),
    '#theme_wrappers' => array('button'),
  );

The #value property is crucial for a submit button, but it's not defined here. Also, things common to all elements like #element_validate won't be anywhere in there.

jhodgdon’s picture

I agree that we could get rid of the element and property names in:

// @element this_element_name
and
// @property bool this_property_name

It would make the parsing slightly more complicated, but yes it could be done. I'm not strongly in favor of either approach.

Regarding the properties that are not defined anywhere, I was just thinking about that too.

For all-element properties, how about if in system_element_info(), we added a "dummy" declaration like this:

// This array is just for documenting properties that do not explicitly appear
// in any element definitions.
$dummy_property_definitions  = array(
  // @property_form_input_all string[] #element_validate
  //   An optional array of functions that will be called to validate the element.
  '#element_validate' => array(),

   (continue with other properties here)
);

For properties that are not globally applicable, we could do something like this:

  // @element_form_input submit
  //   Submit button for a form.
  $types['submit'] = array(
    // @property_form_input_all bool #input
    //   TRUE if this is a form input element. Default: FALSE.
    '#input' => TRUE,
    // @property string #name
    //   The name attribute of the button.
    '#name' => 'op',
    // @property bool #is_button
    //   TRUE if this is a button.
    '#is_button' => TRUE,
    // @property bool #executes_submit_callback
    //   TRUE if when this button is clicked, the form submit callbacks should
    //   always be executed. Used for AJAX processing.
    '#executes_submit_callback' => TRUE,
    '#limit_validation_errors' => FALSE,
    // @property_all string[] #process
    //   Array of names of functions that will be called to process this
    //   element during rendering.
    '#process' => array('form_process_button', 'ajax_process_form'),
    '#pre_render' => array('form_pre_render_button'),
    '#theme_wrappers' => array('input__submit'),

    // Other properties that do not have defaults are listed below.

    // @property string #value
    //   The text to display on the button.

  );

This would be an argument for why it is useful to have the property or element name on the line with the @property/@element tag -- because then if there is no code below it, we could still parse it out.

Thoughts? Sigh. Maybe this is becoming too complicated again and we should go back to #42's idea.

jhodgdon’s picture

Issue summary: View changes

Update current status/proposals for this issue

nevergone’s picture

What can we do to this?

jhodgdon’s picture

Assigned: webchick » Unassigned
Issue tags: +docs infrastructure

I have added this to the agenda for the next meeting of the Documentation Working Group, which is a new Governance group that is at the goal-setting stage.

nevergone’s picture

Something result?

jhodgdon’s picture

No, we haven't figured this out yet.

jhodgdon’s picture

Issue summary: View changes
Status: Needs work » Needs review

I have completely rewritten the issue summary for this issue, outlining the specifications for what we want, and the various proposals that have been made.

We really need to resolve this. The current situation is that we have no documentation for render elements, out of date and unmaintainable documentation for form elements. Not OK.

Any thoughts on the proposals? Are any of them viable? Can we adopt one, flesh it out, and move forward? Please? :)

Status: Needs review » Needs work

The last submitted patch, 54: 1617948-yet-another-proposal.patch, failed testing.

jhodgdon’s picture

Silly testbot, this was a proposal that needs review, not a specific patch. :)

jhodgdon’s picture

Status: Needs work » Needs review
Sutharsan’s picture

Great initiative to revive this issue! After spending five days at DevDays Szeged working on D8 FAPI docs (#2220415: Document new D8 Form API elements), I know that FAPI docs needs a different solution. Next week I will read through the issue (summary) and respond here.

jhodgdon’s picture

Issue summary: View changes

Added historical note to issue summary.

jhodgdon’s picture

Issue summary: View changes

Add strong tags to highlight what each proposed resolution is.

joachim’s picture

I definitely prefer having the documentation close to the code.

I like this part of (d):

> For elements, put the documentation inside the hook_element_info() functions in /** */ comments.

But I am less keen on the yml file for properties. Could we pick a function whose header could document all the common properties?

Or, on a complete tangent, could elements get dummy functions in api.php files?

jhodgdon’s picture

Issue summary: View changes

RE #68 - Each property has a number of components to document (see item 6 in the Requirements section of the summary). So I don't think that putting all the property documentation into one function header (like drupal_render() docs for instance) will work very well, because you'd need to have a bunch of @ tags for each property. This is also why we don't want to put all the elements documentation into the hook_element_info() doc header, because elements also have a lot of components to document (see item 4 in the Requirements section). [This idea is proposal e in the summary by the way, and has been discussed previously on this issue and/or the other one. It's just not really viable.]

Making them into dummy functions in an api.php file... yeah, we could, but they really aren't functions or even remotely close to being functions, so it's fairly weird. We also do not want them to appear in the Functions list on api.drupal.org, I think? Too confusing. But we could do it that way I guess. I'm not totally opposed.

Anyway, I've added this as proposal (g) to the issue summary, and noted on the Element proposals that this is an alternative to YML files.

chx’s picture

Looking into the future where we need documentation for service tags, event names and god knows what else really, I could envision a modulename.documentation.yml with top level keys like service_tags, event_names, render_elements, render_properties etc etc

webchick’s picture

Looking at the proposed options, I think a) and b) should probably both be thrown out as possible options. No offense to whoever proposed them, but we've learned over and over and over (and over!) again that if the docs ain't in the code, they ain't gonna get updated. (And even then, it's spotty, because it requires a human to catch it.)

YAML files to me feel a) too separated from the actual implementation, b) too weird compared to how we document absolutely everything else, which is always PHPDoc. And once again, because of that weirdness, I don't see us catching missing/out-dated docs when we need to. So I don't really like c)

I like the part of d) that talks about documenting the elements at the source (hook_element_info()). That's basically the only way have a hope and prayer of catching missing/incorrect docs. However, it seems like we need the properties documented there as well, or at least the ones specific to those elements. (e.g. #size in the case of textfield.) Most of the others (#access, #disabled, etc.) can be inferred by #input => TRUE.

Here's a radical proposal that I'm not sure I actually agree with. :P Turn elements into actual classes implementing ElementInterface (or whatever) so they're easy to find, and have the properties documented as actual, you know, properties :P in the class. This option wouldn't be back portable to D7 obviously, but it would move hook_element_info away from ArrayPIs which has been the trend elsewhere in the code base for D8, and for D7 whatever is or isn't documented has been that way for 3.5 years so can probably stay in its current state. It probably is way too late for something like this, and the overhead required in either case might make it prohibitive for themers etc. so it'd be a no-go from that respect. But it still feels like we're spending an awful lot of time/energy trying to find a way to document this weird stuff in what's effectively a dead API because in Drupal 9 we're almost assuredly going to ditch the render ArrayPI for something OO.

a.ross’s picture

Here's a radical proposal that I'm not sure I actually agree with. :P Turn elements into actual classes implementing ElementInterface (or whatever) so they're easy to find, and have the properties documented as actual, you know, properties :P in the class.

That actually sounds pretty good. And I think if you plan the design properly, you could re-use most of the code for the classes in the hypothetical new D9 Render API. You could possibly do something like this (not elaborate of course):

/**
 * Element documentation.
 */
class FieldsetElement extends BaseElement {
    /**
     * The fieldset element allows children.
     */
    protected $children;

    /**
     * Property documentation.
     */
    protected $title;

    /**
     * Property documentation.
     */
    protected $collapsible;

    /**
     * Property documentation.
     */
    protected $collapsed;

    public function validate() {
        // Validate if required properties are present.
        return true;
    }

    public function render() {
        return "Rendered HTML";
    }
}

abstract class BaseElement implements ElementInterface {
    /**
     * Creates element class instances from Render API arrays.
     */
    public function __construct(array $element) {
        $this->validate();

        $this->children = element_children($element);

        foreach ($element as $key => $value) {
            if ($key != '' && $key[0] == '#') {
                $this->{substr($key, 1)} = $value;
            }
        }
    }
}
jhodgdon’s picture

Issue summary: View changes

There was discussion early in the D8 coding cycle (and in this issue) about turning elements into plugins or classes or something. But that did not happen. So please do not discuss it here; way out of scope and not happening until Drupal 9. I think there's even an issue link somewhere above in one of the comments. We have completely impossible documentation now, and I really really don't want to wait several more years to resolve this problem. The 7 years that it's already been is plenty.

Regarding YML vs. PHPDoc... Yeah, I think we need to stick with PHPDoc too. (I think we should do this for service tags too; off topic for here.)

Regarding properties... Really it is not possible to document properties completely (with examples etc. like they are in the current Form API reference) inside of another doc block. This is extensively discussed in the Issue Summary and previous comments. They just have to be elsewhere, and I don't think there is any way around it, even though it will probably mean their docs are not updated as often.

So....

OK, here is a full proposal for what I think we should really do. I've noted this in the issue summary.

Elements

[Proposal (f) in the summary] For elements that are defined by modules that have only one element to define, put the element documentation into the docs header for the hook_element_info() implementation. For modules that have multiple elements, change the hook_element_info() implementation so that it calls individual functions, each of which defines one element, and put the docs for elements in those individual functions.

So it would look like this:

// in system_element_info():
$types['textfield'] = _system_element_textfield();

/**
 * Defines a text field form element.
 *
 * Corresponds to an HTML input element, with type="text".
 *
 * Further documentation goes here, like some information about autocompletes.
 *
 * Usage example:
 *    @code ... @endcode
 *
 * @form_input_element textfield
 *
 * @see ...
 */
function _system_element_textfield() {
   return array(
    '#input' => TRUE,
    '#size' => 60,
    '#maxlength' => 128,
    '#autocomplete_path' => FALSE,
    '#process' => array('ajax_process_form'),
    '#theme' => 'textfield',
    '#theme_wrappers' => array('form_element'),
  );
}

The important note here is that to indicate "this is an element", you would include one of these three doc tags, in order from most specific to least (include the most specific one that applies):
- @form_input_element element_name
- @form_element element_name
- @render_element element_name

In the function body, it would automatically show the specific properties, and on api.drupal.org, these would link to property pages.

Properties

[newly-added proposal (h)] For properties, we would make files like system_properties.api.php. Each property would be documented in a documentation block that doesn't have code associated, similar to a @defgroup doc block.

Sample:

/**
 * @property #options List of options for form elements with multiple choices.
 *
 * @property_form_input
 * @property_automatic false
 * @property_internal false
 * @property_name #options
 * @property_value
 *   A simple array of options, or an array whose keys are the internal names and whose values
 *   are the corresponded translated display values.
 * @property_default array()
 * 
 * @see radios.html.twig
 * @see comment_controls()
 */

The important thing here is that each docblock would start with a @property tag [might need to make sure this is a good tag name that isn't used for something else in phpdoc/doxygen first!], similar to @defgroup.

Additional tags would define aspects of the property, like whether it is internal, and whether it is automatically inherited, and what type of property it is (see issue summary "requirements" section for things we need to document).

We would also need a way to document properties that have different docs for different uses of the same name. TBD. But I think we can work this out.

Thoughts?

webchick’s picture

Actually #72 sounds potentially interesting as an option i). I interpret that less of actually doing a full-scale conversion of elements to OO, but more along the lines of what c) or whatever proposed, but instead of pseudo-documenting it in YAML or in weird @customproperties, we put the docs in classes w/ actual properties. It still has the problem of being too separated away from the actual implementation, but at least it's still PHPDoc, and as an added bonus the docs are already there in the proper format for when render/form API does eventually move OO.

Have to review/think about #73 more if that doesn't fly.

joachim’s picture

// in system_element_info():
$types['textfield'] = _system_element_textfield();

I'm trying to think whether instead of hacking up system_element_info(), there's something we can invent in the api.php file to hang these off -- either a dummy function like element_textfield(), or a variable declaration, maybe? I don't know that those are less ugly than splitting up system_element_info() (and forcing any module that wants to implement it and have its elements documented to do the same).

Other than that, I'm happy with #73.

joachim’s picture

> but instead of pseudo-documenting it in YAML or in weird @customproperties, we put the docs in classes w/ actual properties. It still has the problem of being too separated away from the actual implementation, but at least it's still PHPDoc

No more separated than our hook and callback docs in api.php files.

If these classes go in api.php files too, then it would be easier to make them empty classes and document all the properties in the class docblock, maybe?

jhodgdon’s picture

Hm. Mock classes. Maybe... The API module does not make a distinction between real and mock functions (so we have hook_*), and it wouldn't make a distinction for these fake classes either. Would that be confusing? And if we did this, the documentation for the elements would be removed from the declaration of them, which I think is not great.

Regarding splitting up hook_element_info(), this was proposed a LONG time ago because people didn't want to have /** */ comments inside of hook_element_info(). I don't think it's a huge deal to split it up, and splitting it up has the advantage that each element declaration is its own function body, so it's easy for the API module to parse, and therefore figure out which properties are used by each element declaration.

webchick’s picture

Well, hook_elelemt_info() implementations would in that case just get a @see to the mock class(es). So we're still documenting things where they are, more or less. But this way is much more future proof than creating a bunch of underscore-prefixed procedural functions, which many people are going out of their way to obliterate entirely in D8 (see the @deprecated tag). And since the mock classes would live in *.api.php files and show up thus in your IDE, I don't think it's that all that confusing, anymore than a fake function hook_foo_bar being in *.api.php is confusing. Would be good to get more thoughts though, since it's definitely a bit different.

jhodgdon’s picture

One thing I really don't like about #72 is that properties for elements are actually #name elements in arrays. Equating them to class $name properties is ... not great, IMO, since that is not at all how we define/use them, and their names are not $name but #name really.

I also don't think making up fake classes is less future-proof than splitting up hook_element_info() implementations into actual (non-fake) functions. When this was suggested more than a year ago in above comments, David even said we could backport it to 7.x. It doesn't change anything substantive in the code, just takes one function and breaks it up into a number of smaller function calls.

I realize we are trying to get rid of functions and hooks in D8, but this is one area where we didn't do that. If elements do become classes in 8.2 or 9 or whatever, I just don't see that having made fake classes in an api.php file is going to help in any way when the structure of the classes is quite likely to be quite different (they'll most likely be plugins for instance).

chx’s picture

After talking to timplunkett, I would recommend moving hook_element_info into plugins and per Tim's recommendation keep the alter as is (and we can't document the properties only added by alters):

namespace Drupal\system;

/**
 * Juicy textfield doxygen here.
 *
 * @ElementInfo('textfield')
 */
class Textfield {
  /**
   * Hey, look here's the #size documentation.
   */
  protected $size;

  /**
   * {inheritdoc}
   * the test getInfo() methods are being removed so no problems.
   */
  public method getInfo() {
    return array('#size' => $size);
  }
}
nevergone’s picture

I'm thinking, possible Drupal 7 compatible solution?

chx’s picture

Off topic. We haven't been able to find one since 2006 november (i think even older than that but I am not 100% my memory is correct after eight years, but I *think* this was discussed at the Vancouver DrupalCon). Let's find one for D8 and ongoing. Sorry.

jhodgdon’s picture

Regarding #80, what are the chances of this happening any time soon?

We have a very strong need to have documentation for the form/render elements for Drupal 8. Editing the existing, and really outdated at this point, Form API reference document is not happening -- every volunteer who has said they'd maintain the behemoth of a document has given up. So we have at least 20 issues where updates are needed, and no real viable way to make the updates.

So unless someone is volunteering to make elements into plugins for 8.0, and unless core maintainers are on board with committing such a patch, and unless we really think it is going to make it into 8.0, can we at least come up with a solution that we can do with minimal disruption?

xjm’s picture

Priority: Normal » Major
joachim’s picture

> So unless someone is volunteering to make elements into plugins for 8.0, and unless core maintainers are on board with committing such a patch, and unless we really think it is going to make it into 8.0, can we at least come up with a solution that we can do with minimal disruption?

I agree with jhodgdon in #83. We need something that works now, with the way core code is now.

If by some chance, hook_element_info() is revamped and turned into something else before 8.0 is released, we can always adapt the documentation to that.

However, I'm going to raise once more my objection to splitting up hook_element_info() implementations into helper functions for each element.

I really think it's going to lead to confusion and bad DX. Consider the following scenario: contrib module Foobar implements hook_element_info() to define a new element. Various sites use API module to document contrib (and plenty of people including myself use API to document their projects' codebases). Foobar's form elements do not get picked up by API and documented. The author of Foobar module files an issue on API, and is told 'Oh, you need to split your hook_element_info() implementation up in to helper functions, in a way that's not documented in the docs for hook_element_info().

I can understand why we don't like having /** ... */ docblocks inside the function body. But have we considered having several items inside the docblock for the whole of the implementation, along the lines of this:

/**
 * First line yada yada.
 *
 * @element foo
 * ... docs for element foo
 *
 * @element bar
 * ... docs for element bar
 */
function foo_element_info() { ...
jhodgdon’s picture

Ummm "... Oh, you need to split your hook_element_info() implementation up in to helper functions, in a way that's not documented in the docs for hook_element_info()."

Why can't we then just document it in hook_element_info()? If we do this, we can surely add a one-line note to hook_element_info() saying "Note: If you want your elements to be documented, see ..." and write up some docs on how to do that at a URL on drupal.org.

Regarding having several items in the doc block, each one needs to have @tags included, blank lines, paragraphs, etc. I don't think your simple illustration does it justice, and I don't think having them all together will really be all that readable by people; not sure about readable by the API module either.

joachim’s picture

> Why can't we then just document it in hook_element_info()? If we do this, we can surely add a one-line note to hook_element_info() saying "Note: If you want your elements to be documented, see ..." and write up some docs on how to do that at a URL on drupal.org.

It's still lousy DX to have to write a hook implementation as multiple helper functions.

That said, it's not a very commonly implemented hook, and while I feel strongly about this, I definitely don't feel more strongly about it than I care about having all this documented in a sensible and maintainable way, and you're the API module maintainer :)

jhodgdon’s picture

We've been promised plugins for Drupal 8. Let's see if this happens in the next couple of weeks.

tim.plunkett’s picture

Assigned: Unassigned » tim.plunkett

I'm going to work on a proof of concept for this.

tim.plunkett’s picture

jhodgdon’s picture

Project: Drupal core » Drupal Technical Working Group
Version: 8.0.x-dev »
Component: documentation » Code

Coding standards changes are now part of the TWG

metzlerd’s picture

This issue hasn't seemed to make any forward progress in 7 months again. I was really hoping to spend some documentation time during the code sprints at DrupalCon LA. Any chance that will be possible? We seem to be at an impass with regard to just where to place this documentation. If we really do want to get off the island I think that we need to not be expecting to read how to write a d8 form by looking through change logs :).

After reading this, I think chx and jhogden both have the right of it. There is need to include indexes of strings, properties/array structures in documentation and those just arent function's, kind of harkening back to "all the strings".

Is there any way we can make functionless document blocks be included in the api documents as indexes, perhaps with a special tag to connect the indexes

/**
 * @element_info
 * @element foo 
 * Element documentation goes here with examples
 * 
 * @element bar 
 * Element documentation for element bar
 * /

/**
 * Implementation of hook_element_info
*/ 
function foo_element_info()

Whatever we do it should ideally work for all data structures documentation and ideally magic strings too. I think the idea that we can produce API documentation without the ablity to document indexes of magic strings is as realistic as the idea that we can write API's that don't use magic strings. It looks good on paper, but doesn't pan out usually.

Anyway. Think of this as a longwinded bump. I'd be willing to spend a couple days working on form element API docs at DrupalCon if we can figure out what form the documentation could take.

Sutharsan’s picture

For sure we need to work out a form for this documentation. Lets start with one or two examples and experiment with it. Discussing how it will be made accessible via the API documentation gets more practical if we have a few examples.

As far as the content of the documentation goes, I have created it for all elements at: #2220415: Document new D8 Form API elements. But that is in the old (current) API docs format.

jhodgdon’s picture

Project: Drupal Technical Working Group » Drupal core
Version: » 8.0.x-dev
Component: Code » documentation
Issue summary: View changes
Status: Needs review » Active
Issue tags: -Needs backport to D7

So, I have a new idea, which will be much simpler, which will be OK for Drupal 8. I'm also moving this back to Core because I don't think this idea requires acceptance outside of the Core maintainers/developers. And removing the backport tag because it can't be backported.

Here's my idea.

In Drupal 8, we already have classes for all the Form/Render elements. They are annotated with either FormElement or RenderElement, and therefore listed on those class pages already, under "37 elements annotated with...":
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Annotation...
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Annotation...
However neither of those lists is extremely useful, and no one knows about them. Also, these classes do not have all of the information that is currently in the Form API reference.

So what I would like to propose is a fairly straightforward fix for this:

a) The API module would make a new page called Elements. This would be similar to the Functions, Classes, Services, etc. pages that are listed in the right sidebar navigation for Drupal 8. It would collect all of the @FormElement and @RenderElement classes, and make a 2-column list giving the element name that you'd use in a render array, and a link to the class. So it might look like:

Elements

Element name Type Class
button FormElement Button

Like similar tables on api.drupal.org, this would have filters and table heading sorts (see the Functions or Class page for example). The API module would automatically gather these from the existing code/annotation and make the table. No patches to Core (yet!).

b) The API module would make a list like "38 uses of this element" (similar to "25 functions call this function") on each form/render element page. This would give you automatic links to examples of the use of the element. Again, no patches to Core (yet!).

c) Each form/render element class would get a review and documentation update (if necessary) to make sure its documentation includes the following:
- Documentation of its specific properties. We'd talked in previous proposals about having separate property pages, but no one could really agree on this, so let's just make sure each element documents the properties that it specifically uses. We can discuss a format, but I think the simplest thing would be just to do something like this in the class doc block:

 * Properties:
 * - size: The number of characters in the text box (default: 60).
 * - foo: Another property description.

- @see links to any theme templates and other functions/files relevant to rendering that element.
- @see link to the main Render/Form API pages (we'd need to figure out which ones all elements should link to)

I think we could argue that we should be doing (c) in any case... I think that most of the classes already have most of the text -- they would just need Properties documentation. We can discuss the specific format, make a meta issue, and then it would be a good Novice project to fix up all the docs, similar to efforts we did on the Annotation classes etc.

d) We would make sure that the Topics related to form/render API on api.drupal.org tell you to go to the Elements page to discover what the elements are. We would also want to make sure there is documentation somewhere on a topic of the common properties shared by all Render elements, and the extra ones that all Form elements inherit (things like #title and #required for Form elements). This would require a docs patch.

e) I'm putting in a method for each listing page (Services, Classes, Functions, etc.) to have some text at the top of it specific to the branch. We'd want to do this for the Elements page -- make it link to the relevant topics. This would also be a small docs patch.

Thoughts? I've added this as proposal (i) in the issue summary.

Sutharsan’s picture

I agree with making it as simple as possible (but not too simple). We indeed need an overview of elements as a starting point for people who are looking for documentation.
'a' and 'b are the minimum and feasible.

For the in-code documentation ('c') I strongly suggest to add example code. I have witnessed it many times that people copy FAPI code and use that as a starting point. Links to examples in code are good for additional examples, but not as a first time experience. Even in with own development I still use the example code more often than the list of properties.

jhodgdon’s picture

I am not against adding examples... At least if we just add the examples in @code...@endcode tags in the API docs though, they'll be much easier than editing the current FAPI HTML guide, which is horrendous.

The problem with putting the examples directly in the API docs, however, is that they may get out of date, whereas links to examples would be less likely to. Plus, it's duplication... So as a compromise, how about if we say that the docs should have a sentence like:

See [name of function or complete \class\with\namespace::method] for a usage example.

Then users would be one click away from a known actual usage example, rather than having to look through a list and try to find one.

Thoughts?

Sutharsan’s picture

Ok, lets get moving again ;) I made this patch containing documentation for dropbutton and checkboxes as an example and to try things out. I've only used standard doxygen syntax, so it could work without API module changes (have not tested)

I did include example code in @code .. @endcode because (especially in the case of dropbutton) suitable example code was many lines down in a function, not easy accessible for a developer looking for a quick copy paste.

I've chosen to use a list of all properties for 'checkboxes'. Not really sure what to do with the automatically inherited properties. As a developer I just want to know which properties are available, regardless where they come from. Per property it might be interesting to know whether it is inherited, but this all needs to be maintained.

Not sure how the@ref links to the properties will work out, looking through doxygen docs, this looked like a possible solution.

Sutharsan’s picture

After installing API module and parsing Drupal's code and documentation, I discovered that @ref is only supported for in-page references, and number lists are not supported (-# in Doxygen).

jhodgdon’s picture

Yeah, @ref is just for within-one-doc-block links. So this idea is not going to work, too bad!

There is no reason why we cannot update the doc blocks for form/render elements and add more documentation and usage examples -- that sounds like a find idea.

Fabianx’s picture

I think this looks great, #99 what is missing to RTBC that as a new standard?

jhodgdon’s picture

This will not work in that patch suggestion in #97, if that is what you are asking:

+ * Properties:
+ * - @ref property_access "#access"
...

I'm actually not sure what it is supposed to do, but that is not what @ref is for. And then there are some -# lines later in the patch that ... not sure about those either but that is not complyiing with our docs standards.

So. There's no reason we cannot go ahead and update docs for any/all of the form/render element classes. And there's no reason we cannot make a Form/Render Element group/topic and make sure that all these classes have @ingroup elements or whatever in their doc blocks. But the suggested documentation in the patch in #97 is not going to work as it is.

metzlerd’s picture

I would be willing to put some time in this at DrupalCON during the coding sprints. I think the references for properties that are not specific to the checkboxes element in the example do not need to be listed here, provided we can provide a link to the general reference (perhaps via the base class). IMHO it's just extra "noise" for the developer. (e.g. I need to know how to use a checkboxes form element, not how to disable it here). In OO we expect there to be general properties that come from base class implementations.

Do I understand correctly that this is actionable now? Should we be filing documentation issues for specific elements, or is that premature?

Sutharsan’s picture

+ * Properties:
+ * - @ref property_access "#access"
...
I'm actually not sure what it is supposed to do, but that is not what @ref is for.

The @ref property_access "#access" was supposed to be a link to the property_access section of the documentation using #access as link text.

While using D8 documentation at api.drupal.org I realised that the ability to search for form/render element properties would be very handy. Currently we only functions, files and topics. But the first step would definitely be that we have a way to link from form/render element properties to property documentation. I have not found a suitable doxygen command. @property looks like a candidate, is not meant to be a reference to other parts of the documentation. @see provides such a reference. Can we use @param to mark the render property documentation?

And then there are some -# lines later in the patch ...

Number lists were removed from the documentation in #2457273: Number lists are not supported in docs - use bullet lists.

jhodgdon’s picture

So... At this time, the actionable part is:

Make sure that each Form/Render element class is well documented. Each one should contain basically what the existing Form API Reference contains (or something similar for elements not in the old Form API reference). So: a description, and either a usage example or an @see link to a good usage example.

metzlerd’s picture

Shoud it include the @ingroup form_elements reference as well or is that still fuzzy?

Sutharsan’s picture

@mtzlerd, you can use the descriptions of new form/render elements I have prepared in #2220415: Document new D8 Form API elements

jhodgdon’s picture

We do not have a topic yet called form_elements, so we should not have an @ingroup form_elements in any documentation.

And starting from the proposed D8 patch for the Form API docs is probably a good idea. You might want to look at other issues in the Documentation project tagged "FAPI reference" to see what other suggestions people have had for the D8 form API reference too, but for now at least getting more/better docs on the classes would be great. Thanks!

nevergone’s picture

Something idea?

jhodgdon’s picture

Issue summary: View changes

The proposals in the issue summary are outdated since we don't have hook_element_info() any more in Drupal 8.

Also, metzlerd has done a great job of adding some documentation to all of the existing element classes in Drupal 8 on related issue #2486967: [meta] Move/Create Form Element Documentation. All of the classes now have Usage examples and some documentation of their special properties.

So... I still think that proposal (i) in comment #94 is the best idea so far for making a substitute for the Form API reference. It would require:

- API module - #839550: Ability to add documentation headers to global listing pages (Classes, Functions, etc.)

- API module also needs to make a new listing page called Elements (no issue yet), as described in #94, which would list the machine names and classes for each; you'd click through to the class to get the full docs (which are now in pretty good shape, or at least they will be once the remaining two issues there are committed).

- We'd also need to write some documentation for the standard properties of all form/render elements.

Really that is all we would need. It is quite simple.

jhodgdon’s picture

The API module changes have been completed (though not deployed to api.drupal.org yet). See #100680-118: [meta] Make API module generate Form API documentation for details. I'm just going to mark this as a duplicate, since it was only spun off from that issue because we were thinking we'd need to change how hook_element_info() was documented. In 8, we don't have this hook any more, and we're documenting render array stuff on the render element plugin classes, so we don't need a new standard any more and this issue is obsolete.

Issues to work on for Drupal 8 to get the docs finished are the children of #2486967: [meta] Move/Create Form Element Documentation, so this is also partly a duplicate of that issue.

Anyway... we just don't need this issue open any more. Hooray!

jhodgdon’s picture

The list of form/render elements is now up on api.drupal.org -- I think it is complete now, but if not, it should be complete within the next hour as api.drupal.org reparses files (there may be a few left to go):
https://api.drupal.org/api/drupal/elements/8

On #2603818: Add defgroups for listing page headers for api.drupal.org I have a patch that will add a documentation header to that page (as well as the Classes, Namespaces, and Services listing pages). A review of that patch would be greatly appreciated, and would further the cause of having documentation available. Thanks!