PHP developer
If you are high on the new Drupal 4.7 then you may want to take your grain of salt now. The latest release is filled with complications brought on by the new Forms API . Not complicated for the user and not complicated for the originating developers but if you are a PHPer jsut diving into the Drupal code version 4.7 suddenly makes phpNuke code look pleasant. The idea was good, the implementation within the core is badly coded and needs a re-work.
This is where Drupal is going to have to break down and start confessing that there is better code and better ways. Those better ways are OOP in nature and design.
In the case of a Forms API they should have used Smarty or quickHTML forms (PEAR) or any number of Forms Class files out there. But instead they went with their own and here is the result. Incomprehensible complexity and convoluted procedural coding.
This fairly easy to understand code in Drupal 4.6:
<?php
function user_admin_perm($edit = array()) {
if ($edit) {
// Save permissions:
$result = db_query('SELECT * FROM {role} ');
while ($role = db_fetch_object($result)) {
// Delete, so if we clear every checkbox we reset that role;
// otherwise permissions are active and denied everywhere.
db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
foreach ($edit[$role->rid] as $key => $value) {
if (!$value) {
unset($edit[$role->rid][$key]);
}
}
if (count($edit[$role->rid])) {
db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($edit[$role->rid])));
}
}
// Clear the cache, as we might have changed the anonymous user's
// permissions.
cache_clear_all();
menu_rebuild();
drupal_goto($_GET['q']);
}
// Compile role array:
$result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
$roles = array();
while ($role = db_fetch_object($result)) {
$role_perms[$role->rid] = $role->perm;
}
$result = db_query('SELECT rid, name FROM {role} ORDER BY name');
$role_names = array();
while ($role = db_fetch_object($result)) {
$role_names[$role->rid] = $role->name;
}
// Render role/permission overview:
$header = array(t('Permissions'),t('Roles'));
foreach (module_list() as $module) {
if ($perms = module_invoke($module, 'perm')) {
$rows[] = array(array('data' => t('%module module', array('%module' => $module)), 'class' => 'module', 'colspan' => count($role_names) + 1));
asort($perms);
foreach ($perms as $perm) {
$row[] = array('data' => t($perm), 'class' => 'permission');
$output = '<div style="height:160px;width:200px;overflow:auto;">';
foreach ($role_names as $rid => $name) {
$output .= form_checkbox($name, "$rid][$perm", 1, strstr($role_perms[$rid], $perm)).'';
}
$output .= '</div>';
$row[] = $output;
$rows[] = $row;
unset($row);
}
}
}
$output = theme('table', $header, $rows, array('id' => 'permissions'));
$output .= form_submit(t('Save permissions'));
return form($output);
}
?>
Now look like this:
<?php
/**
* Menu callback: administer permissions.
*/
function user_admin_perm($str_rids = NULL) {
if (preg_match('/^([0-9]+[+ ])*[0-9]+$/', $str_rids)) {
// The '+' character in a query string may be parsed as ' '.
$rids = preg_split('/[+ ]/', $str_rids);
}
if($rids) {
$breadcrumbs = drupal_get_breadcrumb();
$breadcrumbs[] = l(t('all roles'), 'admin/access');
drupal_set_breadcrumb($breadcrumbs);
$result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid IN (%s) ORDER BY name', implode(', ', $rids));
}
else {
$result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
}
// Compile role array:
$roles = array();
while ($role = db_fetch_object($result)) {
$role_permissions[$role->rid] = $role->perm;
}
if($rids) {
$result = db_query('SELECT rid, name FROM {role} r WHERE r.rid IN (%s) ORDER BY name', implode(', ', $rids));
}
else {
$result = db_query('SELECT rid, name FROM {role} ORDER BY name');
}
$role_names = array();
while ($role = db_fetch_object($result)) {
$role_names[$role->rid] = $role->name;
}
// Render role/permission overview:
$options = array();
foreach (module_list(FALSE, FALSE, TRUE) as $module) {
if ($permissions = module_invoke($module, 'perm')) {
$form['permission'][] = array('#type' => 'markup', '#value' => t('%module module', array('%module' => $module)));
asort($permissions);
foreach ($permissions as $perm) {
$options[$perm] = '';
$form['permission'][$perm] = array('#type' => 'markup', '#value' => t($perm));
foreach ($role_names as $rid => $name) {
// Builds arrays for checked boxes for each role
if (strstr($role_permissions[$rid], $perm)) {
$status[$rid][] = $perm;
}
}
}
}
}
// Have to build checkboxes here after checkbox arrays are built
foreach ($role_names as $rid => $name) {
$form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status[$rid]);
$form['role_names'][$rid] = array('#type' => 'markup', '#value' => l($name, 'admin/access/'. $rid), '#tree' => TRUE);
}
$form['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
return drupal_get_form('user_admin_perm', $form);
}
function theme_user_admin_perm($form) {
foreach (element_children($form['permission']) as $key) {
// Don't take form control structures
if (is_array($form['permission'][$key])) {
$row = array();
// Module name
if (is_numeric($key)) {
$row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'module', 'colspan' => count($form['role_names']) + 1);
// Permissions
}
else {
$row[] = array('data' => form_render($form['permission'][$key]), 'class' => 'permission');
foreach (element_children($form['checkboxes']) as $rid) {
if (is_array($form['checkboxes'][$rid])) {
$row[] = array('data' => form_render($form['checkboxes'][$rid][$key]), 'align' => 'center', 'title' => t($key));
}
}
}
$rows[] = $row;
}
}
$header[] = (t('Permission'));
foreach (element_children($form['role_names']) as $rid) {
if (is_array($form['role_names'][$rid])) {
$header[] = form_render($form['role_names'][$rid]);
}
}
$output = theme('table', $header, $rows, array('id' => 'permissions'));
$output .= form_render($form);
return $output;
}
?>
Who can make heads or tails out of this? I love arrays. I deal a lot in them as my first PHP coding involved using no databases just flat files and arrays. You learn two things when using arrays on a daily basis. First arrays are wonderful in when coded right but if coded wrong like trying to reassemble spagetti after a handgrenade hits an italian restaurant.
No, you won't be seeing any 4.7 code from me. I think that Drupal should just junk this API and rollback to 4.6. I seriously doubt that this API will get any better to work with even with perfect documentation. There is just too much memory travel involved. Most people can remember seven pieces of information short term. This API requires that you remember at least 15 maybe 50 to start! Plus whatever code you have in front of you and if you don't have an IDE throwing hints at you then you are lost. One of the biggest points that irritate me is the use of #, don't ask me why but I think it just sucks. It's like a certain aquaintence of mine that hates PHP becuase it uses $ on variables. But I guess since the code is already complicated and looks like the ugliest of Perl code, why not just dot the i with #?
Another thing and something I see as a flaw in the design is the use of #prefix and #suffix. These should not be needed. The theming functions should handle any use of HTML. But this goes back a long way. Drupal has always carried the baggage of having too much HTML in its' core PHP. The is one good thing about the Forms API. It will keep developers from plugging in HTML where it should not be. This is because they will not know where to place it.
This article brought to you by the
Hiveminds Magazine - Staff.
Contact us if you want to post an article or announcement anonymously