Hi!

I need to add a contact form to a certain node types where registered and anonymous users can send a message to the node owner. This is actually a classified ad directory where node owner is a registered user who has placed an ad.

I haven't any coder skills but I've managed to get it working - sort of... Code below generates the contact form nicely and submitting works also ok. Code is placed to Display Suite code field, but I suppose it should work in block too.

The problem is, I have noticed that it interferes core search module. Everytime I try to make a search, it gives me white screen and later some errors. If I disable this code, everything works fine. Here's the error:

Notice: Trying to get property of non-object in eval() (line 6 of /var/aegir/platforms/drupal-7.12/modules/php/php.module(80) : eval()'d code).
Notice: Trying to get property of non-object in eval() (line 8 of /var/aegir/platforms/drupal-7.12/modules/php/php.module(80) : eval()'d code).
Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->load() (line 178 of /var/aegir/platforms/drupal-7.12/includes/entity.inc).
Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->cacheGet() (line 354 of /var/aegir/platforms/drupal-7.12/includes/entity.inc).
Notice: Trying to get property of non-object in designlasi_contact_personal_form() (line 27 of /var/aegir/platforms/drupal-7.12/modules/php/php.module(80) : eval()'d code).
Notice: Trying to get property of non-object in eval() (line 6 of /var/aegir/platforms/drupal-7.12/modules/php/php.module(80) : eval()'d code).
Notice: Trying to get property of non-object in eval() (line 8 of /var/aegir/platforms/drupal-7.12/modules/php/php.module(80) : eval()'d code).
Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->load() (line 178 of /var/aegir/platforms/drupal-7.12/includes/entity.inc).
Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->cacheGet() (line 354 of /var/aegir/platforms/drupal-7.12/includes/entity.inc).

I would appreciate help with this one :-)

Here's the code:

<?php
// Get node id
$node = node_load(arg(1));

// Only for certain content types
if (($node->type) == 'buyer' OR 'seller') {

$uid = $node->uid;
$recipient = user_load($uid);

// Load required include
module_load_include("inc", "contact", "contact.pages");

function design_contact_personal_form($form, &$form_state, $recipient) {
  global $user;

  $form = contact_personal_form($form, $form_state, $recipient);

  $node = node_load(arg(1));
  drupal_set_title($node->title);

  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Your name'),
    '#maxlength' => 255,
    '#default_value' => $user->uid ? format_username($user) : '',
    '#required' => TRUE,
    '#size' => 35,
  );

  $form['mail'] = array(
    '#type' => 'textfield',
    '#title' => t('Your e-mail address'),
    '#maxlength' => 255,
    '#default_value' => $user->uid ? $user->mail : '',
    '#required' => TRUE,
    '#size' => 35,
  );

  // Load title
  $form['subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Subject'),
    '#size' => 35,
    '#default_value' => 'Your classified ad',
    '#required' => TRUE,
  );

  $form['message'] = array(
    '#type' => 'textarea',
    '#title' => t('Message'),
    '#required' => TRUE,
    '#rows' => 4,
  );

return($form);
}

function design_contact_personal_form_validate($form, $form_state) {
  return(contact_personal_form_validate($form, $form_state));
}

function design_contact_personal_form_submit($form, $form_state) {
  $form = contact_personal_form_submit($form, $form_state);

  // No redirect
  $form_state['redirect'] = drupal_get_destination();

  return($form);  
}

// Print form
return drupal_render(drupal_get_form('design_contact_personal_form', $recipient)); 

} // End
?>

Comments

WorldFallz’s picture

One thing I see right off the bat... try changing

if (($node->type) == 'buyer' OR 'seller') {

to

if (isset($node) && ($node->type == 'buyer' || $node->type =='seller')) {.

torsti’s picture

Thanks, WorldFallz! One step closer; now I get real results instead of white screen. But there's still one error:

Notice: Trying to get property of non-object in eval() (line 7 of /var/aegir/platforms/drupal-7.12/modules/php/php.module(80) : eval()'d code).

WorldFallz’s picture

impossible to say without knowing what line 7 is (line 7 above is blank).

torsti’s picture

I found it now! I just needed to wrap first line like this:

if (arg(0) == 'node' && is_numeric(arg(1))) {
  $node = node_load(arg(1));
}

No more errors :-D
Thanks for taking time with this!

Web Assistant’s picture

The other members that have replied have bigger brains than me so perhaps they could confirm, but I was wondering if it's better to use menu_get_object instead of node_load

<?php
if ($node = menu_get_object()) {
  $uid = $node->uid;
  // ... etc
}
?>

I think because the menu router already has the node object loaded.

jaypan’s picture

They end up being the same thing - menu_get_object() makes a call to node_load(). In the docs, it doesn't appear that either function caches the result.

Contact me to contract me for D7 -> D10/11 migrations.

Web Assistant’s picture

Hi Jaypan, you are probably right.

Though, I always thought menu_get_object calls menu_get_item, and stores the router item in a static variable..

<?php
$router_items = &drupal_static(__FUNCTION__);
?>

menu_get_item is called initially by menu_execute_active_handler() during the page request and is stored as a static variable, so if you call menu_get_object again it just gets the stored object from drupal_static?

jaypan’s picture

You're right, menu_get_item does store it in memory.

Contact me to contract me for D7 -> D10/11 migrations.

WorldFallz’s picture

Actually, with d7, if you follow node_load it leads back to entity_load:

"The entities are stored in a static memory cache, and will not require database access if loaded again during the same page request."

So it's cached ;-)

jaypan’s picture

I had to dig down to find that, but it happens in DrupalDefaultEntityController::load

// Try to load entities from the static cache, if the entity type supports
  // static caching.
  if ($this->cache && !$revision_id) {
    $entities += $this->cacheGet($ids, $conditions);
    // If any entities were loaded, remove them from the ids still to load.
    if ($passed_ids) {
      $ids = array_keys(array_diff_key($passed_ids, $entities));
    }

Edit: That all said, there are a lot of function calls to get down to this point, whereas calling menu_get_object() only calls two - menu_get_object() and menu_get_item() before it gets to the cache, so it may be a little better, though we are talking a couple of milliseconds at best.

Contact me to contract me for D7 -> D10/11 migrations.

Web Assistant’s picture

Ooh, didn't know that. I did a test..

<?php
// menu_get_object
timer_start('menu_get_object');
menu_get_object();
krumo(timer_read('menu_get_object'));

// node_load
timer_start('node_load');
node_load(arg(1));
krumo(timer_read('node_load'));
?>

menu_get_object always takes around 2.00ms, whereas node_load always takes around 0.08ms. So I guess node_load is the way to go?

jaypan’s picture

Try running those through loops around 10000 times each, and it will give you a more accurate reading - individual load times can vary.

Contact me to contract me for D7 -> D10/11 migrations.

Web Assistant’s picture

Hope I've done this right..

<?php
  $loop = 10000;
  $time = 0;
  for ($i = 1; $i <= $loop; $i++) {
    timer_start('menu_get_object');
    menu_get_object();
    $time += timer_read('menu_get_object');
  }
  krumo($time / $loop);
  
  $time = 0;
  for ($i = 1; $i <= $loop; $i++) {
    timer_start('node_load');
    node_load(arg(1));
    $time += timer_read('node_load');
  }
  krumo($time / $loop);
?>

For 10000 loops:
menu_get_object = 11.642124 ms
node_load = 0.057509 ms

for 5000 loops:
menu_get_object = 6.136584 ms
node_load = 0.05772 ms

I'm doing this on my home computer so probably not massively accurate, though I think there is enough there to convince me to use load_node in future.

jaypan’s picture

That's a good test. node_load() definitely looks to be the better result by a longshot.

Contact me to contract me for D7 -> D10/11 migrations.

WorldFallz’s picture

seriously-- nice test! good to know too.

nevets’s picture

You also might want to look at the Contact Form on Node module.

torsti’s picture

Yes, I tried that module, but it appears not to work for anonymous users :-(

Anonymous’s picture

@torsti I want to do exactly the same thing so where do I place this php code please?