What node_type_get_types()
returns is an associative array of node type objects, keyed by the type. The description of the value returned is more understandable in the _node_types_build()
documentation.
The hook implementation done from a Drupal core module, for example comment_forms()
, helps to understand the correct code.
function comment_forms() {
$forms = array();
foreach (node_type_get_types() as $type) {
$forms["comment_node_{$type->type}_form"]['callback'] = 'comment_form';
}
return $forms;
}
In your case, the code should be similar to the following one.
function my_dossier_forms($form_id, $args) {
$forms = array();
foreach (node_type_get_types() as $type) {
$forms["my_dossier_node_{$type->type}_form"]['callback'] = 'my_dossier_form';
}
return $forms;
}
This code isn't much different from the code shown in the question, and it would not cause, alone, the class 'my_dossier_form' not found error.
The line 844 is the following one.
$form = call_user_func_array(isset($callback) ? $callback : $form_id, $args);
$callback
is initialized from the following code.
if (!isset($forms) || !isset($forms[$form_id])) {
$forms = module_invoke_all('forms', $form_id, $args);
}
$form_definition = $forms[$form_id];
if (isset($form_definition['callback arguments'])) {
$args = array_merge($form_definition['callback arguments'], $args);
}
if (isset($form_definition['callback'])) {
$callback = $form_definition['callback'];
$form_state['build_info']['base_form_id'] = isset($form_definition['base_form_id']) ? $form_definition['base_form_id'] : $callback;
}
Line 844 could not think my_dossier_form
is a class, except in the case $callback
contains an array like array('my_dossier_form', 'mymodule_form');
, or it contains a string like 'my_dossier_form::methodName'
.
The warnings about an array to string conversion means Drupal is getting an array when it expects a string, for example from the following line (line 1094).
elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_validate')) {
I would just avoid returning a form ID that starts with $type
as that is probably creating conflicts with other modules implementing hook_forms()
, which are expected to return a unique form ID each. See module_invoke_all()
to understand what happens when two hook_forms()
implementations return information for the same form ID.
foreach (module_implements($hook) as $module) {
$function = $module . '_' . $hook;
if (function_exists($function)) {
$result = call_user_func_array($function, $args);
// In the case of hook_forms(), $result contains an array.
if (isset($result) && is_array($result)) {
$return = array_merge_recursive($return, $result);
}
elseif (isset($result)) {
$return[] = $result;
}
}
}
To be more exact, two modules returning values for the same form ID could at least cause the call_user_func_array() expects parameter 1 to be a valid callback, class '[callback]' not found when they both set the value for the same callback. See the output of the following code, to understand what exactly happens.
$return["type_node_form"]["callback"] = "my_dossier_form";
$result["type_node_form"]["callback"] = "mymodule_form";
print_r(array_merge_recursive($return, $result));
The callback value becomes an array of two strings, which call_user_func_array()
interprets as an array containing a class name and a method name.
Array
(
[type_node_form] => Array
(
[callback] => Array
(
[0] => my_dossier_form
[1] => mymodule_form
)
)
)
In this case, the conflict is with the Node module, which uses the following code for its hook_forms()
implementation.
function node_forms() {
$forms = array();
if ($types = node_type_get_types()) {
foreach (array_keys($types) as $type) {
$forms[$type . '_node_form']['callback'] = 'node_form';
}
}
return $forms;
As side note, the hook_forms()
purpose is providing the same form builder for a group of forms whose ID follow a schema, such as in the case of comment edit forms, whose IDs are comment_node_[node type]_form. When provided, the form builder callback (passed as callback value) should build the full form, not part of it.
The fact my_dossier_form()
builds just a submission button, and my_dossier_forms()
is using the same code used by node_forms()
makes me think the code purpose is altering the node edit forms, which should be accomplished by implementing hook_form_BASE_FORM_ID_alter()
. That's what the Book module does with book_form_node_form_alter()
, which is invoked for the node edit form of every content type.
function book_form_node_form_alter(&$form, &$form_state, $form_id) {
$node = $form['#node'];
$access = user_access('administer book outlines');
if (!$access) {
if (user_access('add content to books') && (!empty($node->book['mlid']) && !empty($node->nid) || book_type_is_allowed($node->type))) {
// Already in the book hierarchy, or this node type is allowed.
$access = TRUE;
}
}
if ($access) {
_book_add_form_elements($form, $form_state, $node);
// Since the "Book" dropdown can't trigger a form submission when
// JavaScript is disabled, add a submit button to do that. book.css hides
// this button when JavaScript is enabled.
$form['book']['pick-book'] = array(
'#type' => 'submit',
'#value' => t('Change book (update list of parents)'),
'#submit' => array(
'book_pick_book_nojs_submit',
),
'#weight' => 20,
);
}
}
If then the hook needs to use the content type name, that is available in $form['#node']->type
.
hook_form_alter
?my_dossier_form()
. What file is this function in? You may need to explicitly include it.hook_forms()
(a.k.a. the callback value) should build the full form, not just a submission button. It seems the OP's task is altering the node edit forms, for whichhook_form_BASE_FORM_ID()
is the hook to implement.