| Project: | Drupal core |
| Version: | 8.x-dev |
| Component: | documentation |
| Category: | task |
| Priority: | normal |
| Assigned: | webchick |
| Status: | needs work |
| Issue tags: | coding standards, needs backport to D7 |
Issue Summary
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 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.
Proposed resolution
1. Move the documentation of form/render array elements/properties into the core source code (documentation headers -- exact format to be determined -- see sections below).
2. Have the API module parse these documentation headers and generate a page substantially similar to the current FAPI reference (and probably a separate page as a render API reference, which doesn't currently exist at all). There's a separate issue about having the API module do this:
#100680: Automatically generate Forms API & other big array documentation
Current proposal for property documentation
In the current FAPI reference, each Property has its own documentation section, with Description, Values, a Usage example, and a list of which elements use that property.
Our current idea on how to replace this is that we probably only need a data type and a one-paragraph description. [Presumably, the API module will be able to generate a "functions that use this property" page, and the "elements that use this" list. And we decided property descriptions didn't need to be extremely extensive.]
With that in mind, we can define new @-tags for properties, and add them to documentation headers like this:
* @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.This consists of:
- A tag, one of:
- @render_property_all - properties used by all render elements, which should be added to the documentation of drupal_render().
- @render_property_common - properties used by some, but not all, render elements, which should be added to the documentation of drupal_render().
- @render_property_internal - properties used internally by the rendering system, which should be added to the documentation of drupal_render().
- @form_property_all - properties used by all elements that are part of forms, which should be added to the documentation of drupal_build_form().
- @form_property_input - properties used by all form input elements, which should be added to the documentation of drupal_build_form().
- @form_property_common - properties used by some, but not all form elements, which should be added to the documentation of drupal_build_form().
- @form_property_internal - properties used internally during form processing, which should be added to the documentation of drupal_build_form().
- @render_property - properties used specifically by one render/form element, or whose standard definition is overridden by a render/form element. Documentation is within the render/form element documentation (see below).
- Data type - same convention as providing @param/@return/@var data types.
- Property name, starting with #
- Description (one paragraph, indented)
Current proposal for element documentation
There is still some disagreement on what to do about element documentation. Basic needs:
- Not limited to one paragraph -- we want to be able to use @code, @see, etc. and multiple paragraphs in element documentation.
- Some way to list which properties are used by the element (although we wouldn't want to have to list all of the common-to-all properties -- we just want to list the specific properties for this element, and the properties whose definitions are non-standard).
Thus, the documentation block should look something like this:
/**
* 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
*/Notes:
- First line description and optional longer description (as in function docs)
- After the description, include a line telling what type of element it is: @input_element (for form input elements only) or @render_element (for all other elements), 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 _common form/element properties this element makes use of in its default rendering (if any). Do not include *_all, *_input, or *_internal properties.
- 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 (see properties section above).
- Include @see references to one or more good illustrative examples of where this element is used, and to theme and preprocess functions. [Presumably, the API module will be able to generate a "functions that use this element" page.]
- Include @ingroup elements [exact group name TBD!!] to indicate this is an element to be included in the Form/Render API elements list.
Where to put the element documentation???
The main remaining question is where to put this documentation block. Proposed ideas:
- As part of the documentation block for the theme or preprocess function for this element. We have pretty much abandoned this idea, because it would not be possible to separate out the documentation for this function and the documentation for the element. [Proposals: comment #1, #8]
- Immediately before the declaration of the element inside of a hook_element_info() implementation. This idea ran into some opposition, because we don't normally have /** */ documentation blocks within functions, and it causes some problems. [Proposals: comment #14. Vehement opposition: comment #19, #28]
- Separating out the individual element declarations in system_element_info() into their own functions, and putting the element documentation there. Other hook_element_info() functions that only define a single element could have the element documentation added to that function header directly. This runs into the same problems as putting the element documentation into the theme function, but it's not quite as bad, since these small functions do not have any purpose except to declare an element, so there is not much function documentation to separate out from the element documentation. [Proposal: comment #21]
- Putting the element documentation blocks into a separate file (system_elements.api.php or something like that). The disadvantage of this idea is that it makes the documentation for elements separate from the declaration/code, and this leads to the documentation not being updated (as has been our experience with having hook documentation in .api.php files).
Remaining tasks
A. Decide on and adopt a standard for the documentation headers. Deciding where to put the headers for elements is the one remaining question to be answered (see Proposed Resolution section above).
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 as documentation headers.
C. Make the API module parse and display this documentation information (separate issue #100680: Automatically generate Forms API & other big array documentation).
User interface changes
No Drupal UI changes.
API changes
No Drupal API changes.
Comments
#1
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: Automatically generate Forms API & other big array 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).
#2
Thanks for resurrecting this topic with a concrete proposal.
* @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.
#3
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.
#4
Oh, and one more thing regarding:
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?).
#5
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).
#6
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).
#7
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 :)
#8
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.html/7#password
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.
---
#9
#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.
#10
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:
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: Automatically generate Forms API & other big array 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:
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.
#11
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.
#12
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.
#13
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: Automatically generate Forms API & other big array 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.
#14
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.
---
#15
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#16
#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"
#17
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.
#18
So.... Does anyone besides jn2 and myself want to comment on this standard before we officially adopt it?
#19
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.
#20
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.
#21
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:
<?php
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.
#22
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? :)
#23
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.
#24
*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/implementations/hook_element_info/7
(not just system_element_info()). And any contrib modules that wanted to comply with the new standards.
#25
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.
#26
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.
#27
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.
#28
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.
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.
#29
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?
#30
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.
#31
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.
#32
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? :)
#33
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 selectis that it acts as an alias forsystem_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.
#34
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.
#35
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. :)
#36
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!
#37
What would there be need for in order for the solution of the issue to go on? Drupal 7 port is coming soon?
#38
We asked webchick to comment and we're waiting for her to do so. Otherwise, we are apparently at an impasse.
#39
Hit the same problems when documenting the new langugae_select element with @LoMo at #1739876: Document new language_select field type.
#40
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.
#41
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.
#42
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.
#43
[double post with #42]
#44
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).
#45
I really really like the patch in #42 :) Simplicity++
#46
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.
#47
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.
#48
For that question, we'd be better off to ask David, as the D7 release manager. Re-assigning to him for a moment.
#49
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 (upgrade path and followup) 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... :)
#50
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 ;)
#51
And now…? :S