I have written my first module and it doesn't work. I run it using localhost/drupal/dbread and it gives 'Page not found' but if there is amistake in my code it tells me. Ho does Drupal manage to find the module and pick out mistakes yet it can't find it? Yes, I have an info file. The module is located at /sites/all/modules/custom/dbread which I beleive is correct. Here's the module

<?php
// $Id$
/**
   * @file
   * Reads a database 
 */
/**
 * Implementation of hook_menu
 */
function dbread_menu() {
 $items['dbread'] = array( 
 'title' => 'Read a database', 
 'page callback' => 'node_select',
 'access callback' => 'true',
 'type' => MENU_NORMAL_ITEM, );
};
$type = 'blog';
$status = 1; 
function node_select($type, $status) {
$sql = "SELECT * FROM {node} WHERE type = '%s' AND status = %d";
$result = db_query(db_rewrite_sql($sql), $type, $status);
while ($data = db_fetch_object($result)) {
$node = node_load($data->nid);
print node_view($node, TRUE);
};
}
node_select($type, $status);

Can anybody tell me what I am doing wrong

Comments

j_ten_man’s picture

Classic mistake (I still do this sometimes). You forgot to return the $items array from hook_menu. That is the first issue. Next up, you don't need to print in your callback. Here is what you should probably do:

// $Id$
/**
   * @file
   * Reads a database 
*/
/**
* Implementation of hook_menu
*/
function dbread_menu() {
  $items['dbread'] = array( 
    'title' => 'Read a database', 
    'page callback' => 'node_select',
    'page arguments' => array('blog', 1), //Pass these here so that when you visit "dbread" they are passed along
    'access callback' => 'true',
    'type' => MENU_NORMAL_ITEM, 
  );
  return $items; //You forgot this
};

function node_select($type, $status) {
  $output = '';
  $sql = "SELECT * FROM {node} WHERE type = '%s' AND status = %d";
  $result = db_query(db_rewrite_sql($sql), $type, $status);
  while ($data = db_fetch_object($result)) {
    $node = node_load($data->nid);
    $output .= node_view($node, TRUE); //Don't use "print" in your page callback (the only time to use "print" is if this were an AJAX callback)
  };
  return $output; //Return the output that you would like to display and Drupal will print it out for you
}
gleble’s picture

Thanks , should have been obvious you've got to return something.

Still not quite right. I get access denied.
warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'true' was given in /opt/lampp/htdocs/drupal/includes/menu.inc on line 452.

I presume it's this line:

'access callback' => 'true',

I've tried various options but nothig works

swentel’s picture

You need provide an existing function for the access callback, not a boolean. Try using access arguments => array('access content') and leave out access callback, it will default to user_access then.

grobemo’s picture

You can actually use a boolean value for the access callback (see http://drupal.org/node/109157), though I'd recommend the method swentel suggests. (I forgot that 'access callback' => 'user_access' is usually unnecessary.)

grobemo’s picture

I've had trouble with the access callback before, too.

First thing to try: Use 'access callback' => true with no quotation marks around true. You want to set the callback to a boolean value, not a string containing the word 'true'.

You could also use:

'access callback' => 'user_access',
'access arguments' => array('access content'),

That means that any user who has permission to "access content" will have permission to view the output from this menu item.

gleble’s picture

I've got over the access problem now I've got a menu item and a page saying 'Read a database' but no outpuy from thr sql part. Is my sql OK.?

<?php
// $Id$
/**
   * @file
   * Reads a database
*/
/**
* Implementation of hook_menu
*/
function dbread_menu() {
  $items['dbread'] = array(
    'title' => 'Read a database',
    'page callback' => 'node_select',
    'page arguments' => array('page', 1), //Pass these here so that when you visit "dbread" they are passed along
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items; //You forgot this
};


function node_select($type, $status) {
  $output = '';
  $sql = "SELECT * FROM {node} WHERE type = '%s' AND status = %d";
  $result = db_query(db_rewrite_sql($sql), $type, $status);
  while ($data = db_fetch_object($result)) {
    $node = node_load($data->nid);
    $output .= node_view($node, TRUE); 
  };
  return $output; //Return the output that you would like to display and Drupal will print it out for you
}
grobemo’s picture

The SQL looks fine.

I suspect the problem is in 'page arguments' => array('page', 1), in dbread_menu. I take it your want to pass the number 1 to node_select for $status. But what you're actually passing is part of the path. hook_menu breaks a path like my_module/foo/bar into an array that looks like this:

0 => my_module
1 => foo
2 => bar

So, if you defined a menu item for my_module/foo/bar and passed array('page',1) to 'page arguments', the second passed to your callback function would be 'foo', not 1.

Try going to http://YOURPATHHERE/dbread/1. Does that get you what you want?

gleble’s picture

OK I can pass the arguments in the URL (I have to do both to make it work i.e. ...dbread/page/1) but now I get two pink bars with n/a written on them. I've looked in my database and there are two nodes with type=page and status=1 so why do I get this strange result.

How can I pass the parameters without using the URL i.e. in the code?

Side point: Can you post screenshot attachments on this forum?

grobemo’s picture

1. The two pink bars with n/a are weird. What do you see in the source code? My best guess is that it's a filter problem. Do you get the same result if you're logged in as user 1 as you do when you're not logged in at all?

2. I wondered why you were trying to pass 'page' and 'status' to the function at all, but I figured that it was just part of learning Drupal. Why not do the following?

<?php
/**
* Implementation of hook_menu
*/
function dbread_menu() {
  $items['dbread'] = array(
    'title' => 'Read a database',
    'page callback' => 'node_select', // No 'page arguments'
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items; //You forgot this
};


function node_select() { 
  $output = '';
  $sql = "SELECT * FROM {node} WHERE type = 'page' AND status = 1"; // hard code 'page' and 1 into the SQL
  $result = db_query(db_rewrite_sql($sql));
  while ($data = db_fetch_object($result)) {
    $node = node_load($data->nid);
    $output .= node_view($node, TRUE); 
  };
  return $output; //Return the output that you would like to display and Drupal will print it out for you
}
?>

I did two things here: First, I got rid of 'page arguments' in hook_menu. Second, I hardcoded 'page' and 1 into the SQL in node_select. If these things aren't going to depend on user input, there's no need to pass them in as arguments at all. If you want to be able to retrieve different node types (e.g., page, story, etc.) using the same function, then they should be passed in from the URL (e.g., dbread/page, dbread/story, etc.), as you did before.

3. As far as I know, you can't post screenshots here. If you can post them somewhere else on the web, you can always link to them.

gleble’s picture

You're right I'm using it to learn. Don't know where the pink bars were from but they're gone.

gleble’s picture

I just changed the node_select function to try to read from the node_access table.
This is what I did

function node_select() {
  $output = '';
  $sql = "SELECT nid FROM {node_access} WHERE 'grant_view' = 1"; 
  $result = db_query(db_rewrite_sql($sql));
  while ($data = db_fetch_object($result)) {
    $node = node_load($data->nid);
    $output .= node_view($node, TRUE);
  };

  return $output; 
}

It doesn't work. Any ideas?

grobemo’s picture

Remove the single quotation marks around grant_view in your SQL.

As it is, you're asking the database to return rows where the string 'grant_view' is equal to the number 1, so it's returning 0 rows every time.

The line in your code should be:

$sql = "SELECT nid FROM {node_access} WHERE grant_view = 1";
gleble’s picture

Got there, all working.