Node-type specific callbacks (*_load(), *_insert(), *_update(), *_form(), etc.) are not really hooks, but a rather crude implementation of a strategy pattern. Those doesn't fall on the scope of #363787: Plugins: Swappable subsystems for core, but we can still use a proper strategy pattern for that.
/**
* Implementation of a custom node type.
*/
interface DrupalNodeType {
/**
* Load node-type-specific information.
*
* This method allow the module to load extra information that it stores about
* a node. It should not be used to replace information from the core {node}
* table since this may interfere with the way nodes are fetched from cache.
*
* @param $nodes
* An array of the nodes being loaded, keyed by nid. At call time,
* node.module has already loaded the basic information about the nodes, such
* as node ID (nid), title, and body.
*
* For a detailed usage example, see node_example.module.
*/
public function load($nodes);
/**
* Respond to node insertion.
*
* This method allows the module to take action when a new node is being
* inserted in the database by, for example, inserting information into
* related tables.
*
* @param $node
* The node being inserted.
* @return
* None.
*
* To take action when nodes of any type are inserted (not just nodes of
* the type(s) defined by this module), use hook_node() instead.
*
* For a detailed usage example, see node_example.module.
*/
public function insert($node);
/**
* Respond to node updating.
*
* This method allows the module to take action when an edited node is being
* updated in the database by, for example, updating information in related
* tables.
*
* @param $node
* The node being updated.
* @return
* None.
*
* To take action when nodes of any type are updated (not just nodes of
* the type(s) defined by this module), use hook_node() instead.
*
* For a detailed usage example, see node_example.module.
*/
public function update($node);
/**
* Respond to node deletion.
*
* @param &$node
* The node being deleted.
* @return
* None.
*
* To take action when nodes of any type are deleted (not just nodes of
* the type defined by this module), use hook_node() instead.
*
* For a detailed usage example, see node_example.module.
*/
public function delete(&$node);
/**
* Display a node.
*
* This method allows a module to define a custom method of displaying its
* nodes, usually by displaying extra information particular to that node type.
*
* @param $node
* The node to be displayed.
* @param $teaser
* Whether we are to generate a "teaser" or summary of the node, rather than
* display the whole thing.
* @return
* $node. The passed $node parameter should be modified as necessary and
* returned so it can be properly presented. Nodes are prepared for display
* by assembling a structured array in $node->content, rather than directly
* manipulating $node->body and $node->teaser. The format of this array is
* the same used by the Forms API. As with FormAPI arrays, the #weight
* property can be used to control the relative positions of added elements.
* If for some reason you need to change the body or teaser returned by
* node_prepare(), you can modify $node->content['body']['#value']. Note
* that this will be the un-rendered content. To modify the rendered output,
* see hook_node($op = 'alter').
*
* For a detailed usage example, see node_example.module.
*/
public function view($node, $teaser = FALSE);
/**
* Prepare a node to be rendered on the node form.
*
* @param &$node
* The node being prepared.
* @return
* None.
*/
public function prepare(&$node);
/**
* Display a node editing form.
*
* This method is called to retrieve the form that is displayed when one
* attempts to "create/edit" an item. This form is displayed at the URI
* http://www.example.com/?q=node/<add|edit>/nodetype.
*
* @param &$node
* The node being added or edited.
* @param $form_state
* The form state array. Changes made to this variable will have no effect.
* @return
* An array containing the form elements to be displayed in the node
* edit form.
*
* The submit and preview buttons, taxonomy controls, and administrative
* accoutrements are displayed automatically by node.module. This hook
* needs to return the node title, the body text area, and fields
* specific to the node type.
*
* For a detailed usage example, see node_example.module.
*/
public function form(&$node, $form_state);
/**
* Verify a node editing form.
*
* This method allows the module to verify that the node is in a format valid
* to post to the site. Errors should be set with form_set_error().
*
* @param $node
* The node to be validated.
* @param $form
* The node edit form array.
* @return
* None.
*
* To validate nodes of all types (not just nodes of the type(s) defined by
* this module), use hook_node() instead.
*
* Changes made to the $node object within a hook_validate() function will
* have no effect. The preferred method to change a node's content is to use
* hook_submit() or hook_node($op='submit') instead. If it is really
* necessary to change the node at the validate stage, you can use function
* form_set_value().
*
* For a detailed usage example, see node_example.module.
*/
public function validate($node, &$form);
/**
* Define access restrictions.
*
* @param $op
* The operation to be performed. Possible values:
* - "create"
* - "delete"
* - "update"
* - "view"
* @param $node
* The node on which the operation is to be performed, or, if it does
* not yet exist, the type of node to be created.
* @param $account
* A user object representing the user for whom the operation is to be
* performed.
* @return
* TRUE if the operation is to be allowed;
* FALSE if the operation is to be denied;
* NULL to not override the settings in the node_access table, or access
* control modules.
*
* The administrative account (user ID #1) always passes any access check,
* so this hook is not called in that case. If this hook is not defined for
* a node type, all access checks will fail, so only the administrator will
* be able to see content of that type. However, users with the "administer
* nodes" permission may always view and edit content through the
* administrative interface.
*
* For a detailed usage example, see node_example.module.
*/
public function access($op, $node, $account);
}
Comments
Comment #1
david straussI wouldn't even call it a "strategy pattern." Modules implementing node types are basically subclassing a generic "node" class that currently has a title and body.
Thus, if we want to do this right, the node module should have a class that it uses for its own (title + body) node types, and modules creating customized node types should subclass it. Then, we use the factory pattern for getting the right node class for any node.
Comment #2
mfer commentedSubscribe.
Comment #3
Crell commentedInterfaces should be named SomethingInterface, per all of the other interfaces in core.
That said, I disagree with David in #1. Node types should not be subclasses. That's far too brittle given how much sideways stuff we do in Drupal. I'd actually argue the other direction: With fields in core, pseudo-hook_load et al should go away entirely and everything should be done through fields. Of course, that requires a very flexible field API so that all that wacky custom code can be reimplemented as custom wacky fields. :-)
Comment #4
david strauss@Crell Yes, I've been known to argue that as well. I was simply suggesting something less radical for now.
Comment #5
xanoSubscribing.
Comment #6
sunComment #7
Crell commentedI think this already did happen in perhaps a roundabout fashion, no? It certainly doesn't apply anymore in the new Entity API...