<?php
// $Id: vehicle.module,v 1.26 2008/10/9 13:40:00 michaelphipps Exp $
/**
* @node_vehicle
* This module defines a custom node type with a custom make / model form element
* that is managed via taxonomy.
*
* No Database required
*/
/**
* Implementation of hook_node_info().
*/
function node_vehicle_node_info() {
return array(
'vehicle' => array(
'name' => t('Vehicle'),
'module' => 'node_vehicle',
'description' => t("This is an Vehicle type with a few fields."),
'has_title' => TRUE,
'title_label' => t('Example Title'),
'has_body' => TRUE,
'body_label' => t('Example Body'),
)
);
}
/**
* Implementation of hook_menu().
*
* Provide a simple menu hook to access the javascript function.
*/
function node_vehicle_menu() {
$items['vehicle/js'] = array(
'type' => 'MENU_CALLBACK',
'page callback' => 'node_vehicle_makemodel_javascript',
'access arguments' => array('access content'),
);
return $items;
}
/**
* Implementation of hook_access().
*/
function node_vehicle_access($op, $node, $account) {
if ($op == 'create') {
return user_access('create vehicle content', $account);
}
if ($op == 'update') {
if (user_access('edit any vehicle content', $account) || (user_access('edit own vehicle content', $account) && ($account->uid == $node->uid))) {
return TRUE;
}
}
if ($op == 'delete') {
if (user_access('delete any vehicle content', $account) || (user_access('delete own vehicle content', $account) && ($account->uid == $node->uid))) {
return TRUE;
}
}
}
/**
* Implementation of hook_perm().
*/
function node_vehicle_perm() {
return array(
'create vehicle content',
'delete own vehicle content',
'delete any vehicle content',
'edit own vehicle content',
'edit any vehicle content',
);
}
/**
* Implementation of hook_elements().
*/
function node_vehicle_elements() {
$type['makemodel'] = array(
'#input' => TRUE,
'#process' => array('node_vehicle_makemodel_expand'),
'#element_validate' => array('node_vehicle_makemodel_validate'),
'#default_value' => array('make' => '', 'model' => ''),
);
return $type;
}
/**
* The process callback to expand the makemodel control.
*/
function node_vehicle_makemodel_expand($element) {
$element['#tree'] = TRUE;
if ( !isset($element['#value']) ) {
$element['#value'] = array('make' => '', 'model' => '');
}
// Get the list of makes from the make/models vocabulary
$vid = 1;// Should the user choose their Taxonomy category?
$parent = 0;
$max_depth = 1;
$makes = taxonomy_get_tree($vid, $parent, -1, $max_depth);
foreach ($makes as $make) {
$make_options[$make->tid] = $make->name;
}
if ( isset($element['#value']['make']) ) {
$models = taxonomy_get_tree($vid, $element['#value']['make'], -1, $max_depth);
foreach ($models as $model) {
$model_options[$model->tid] = $model->name;
}
}
else {
$model_options = array();
}
$element['make'] = array(
'#type' => 'select',
'#value' => $element['#value']['make'],
'#options' => $make_options,
'#attributes' => array('onchange' => 'changeModel();'),
);
$element['model'] = array(
'#type' => 'select',
'#value' => $element['#value']['model'],
'#options' => $model_options,
);
return $element;
}
/**
* Our element's validation function.
*
* Not currently being used, because I'm unsure what validation I need to do on taxonomy
* data and if it is even needed at all.
*/
function node_vehicle_makemodel_validate($form, &$form_state) {
if ( isset($form['#value']['make']) ) {
if (0 == 1) {
form_error($form['make'], t('Please select a make.'));
}
}
if ( isset($form['#value']['model']) ) {
if (0 == 1) {
form_error($form['model'], t('Please select a model.'));
}
}
return $form;
}
/**
* Theme function to format the output.
*
* We use the container-inline class so that all three of the HTML elements
* are placed next to each other, rather than on separate lines.
*/
function theme_makemodel($element) {
return theme('form_element', $element, '<div class="container-inline">'. $element['#children'] .'</div>');
}
function node_vehicle_makemodel_javascript() {
// Getting the list of makes from the make/models vocabulary
$vid = 1 ; // Should the user choose their Taxonomy category?
$parent = 0;
$max_depth = 1;
$makes = taxonomy_get_tree($vid, $parent, -1, $max_depth);
foreach ($makes as $make) {
$make_options[$make->tid ] = $make->name;
}
unset($temp);
$content .= "model = new Array();\n";
$result = db_query("SELECT term_data.tid AS id, term_hierarchy.parent AS parentid, term_data.name AS model FROM {term_data} join {term_hierarchy} ON (term_data.tid = term_hierarchy.tid) WHERE term_data.vid=1 AND term_hierarchy.parent >0 ORDER BY parentid, model");
while ($models = db_fetch_object($result)) {
if ( $temp == $models->parentid ) {
$content .= ",";
}
else {
if ( isset($temp) ) $content .= ");\n";
$temp=$models->parentid;
$content .= "model[$temp] = new Array(\n";
}
$content .= "'". $models->model ."',". $models->id ."\n";
}
$content .= ");\n";
$content .= '//change model
function changeModel(){
var objMake = document.getElementById("edit-makemodel-make");
var objModel = document.getElementById("edit-makemodel-model");
var make_id = objMake[objMake.selectedIndex].value;
//clear model select
oldLength = objModel.length;
for (i = oldLength; i >= 0; i--) objModel.options[i] = null;
//build model select
if (make_id=="")
objModel.options[0] = new Option("Any model","");
else
for (i = 0; i <= model[make_id].length-1; i=i+2)
objModel.options[i/2] = new Option(model[make_id][i],model[make_id][i+1]);
}
';
header("Content-type: text/javascript");
print $content;
exit();
}
/**
* Implementation of hook_form().
*
* Describe the form for collecting vehicle information.
*/
function node_vehicle_form(&$node) {
// The site admin can decide if this node type has a title and body, and how
// the fields should be labeled. We need to load these settings so we can
// build the node form correctly.
$type = node_get_types('type', $node);
if ($type->has_title) {
$form['title'] = array(
'#type' => 'textfield',
'#title' => check_plain($type->title_label),
'#required' => TRUE,
'#default_value' => $node->title,
'#weight' => -5
);
}
if ($type->has_body) {
$form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
}
// Add the javascript to make the make/model selection work properly
drupal_add_js('vehicle/js');
// Now we define the form elements specific to our node type.
$form['makemodel']= array(
'#type' => 'makemodel',
'#title' => t("Make/Model"),
'#default_value' => array('make' => $node->make, 'model' => $node->model),
'#description' => t('Select a vehicle make and model.'),
);
return $form;
}
/**
* Implementation of hook_validate().
*
* Again, unsure if I need this since I am collecting taxonomy tids from select boxes.
*/
function node_vehicle_validate(&$node) {
// include validation logic (if required)
}
/**
* Implementation of hook_insert().
*
* Saves the taxonomy details from the makemodel field.
*/
function node_vehicle_insert($node) {
taxonomy_node_save($node, $node->makemodel);
}
/**
* Implementation of hook_update().
*
* Saves the taxonomy details from the makemodel field
*/
function node_vehicle_update($node) {
// if this is a new node or we're adding a new revision,
if ($node->revision) {
node_vehicle_insert($node);
}
taxonomy_node_save($node, $node->makemodel);
}
/**
* Implementation of hook_nodeapi().
*
* When a node revision is deleted, we need to remove the corresponding record
* from our table. The only way to handle revision deletion is by implementing
* hook_nodeapi().
*/
function node_vehicle_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
case 'delete revision':
// Do taxonomy terms get removed automatically? If so, nothing is required here
break;
}
}
/**
* Implementation of hook_delete().
*
* When a node is deleted, we need to remove all related records from out table.
*/
function node_vehicle_delete($node) {
// No logic is required here at this moment
}
/**
* Implementation of hook_load().
*
* Need to separate the vehicle terms into separate make / model elements
* so they can be used to populate existing nodes
*/
function node_vehicle_load($node) {
$vid=1;
$make_model_array = taxonomy_node_get_terms_by_vocabulary($node, $vid);
foreach ($make_model_array as $key => $value) {
if ( taxonomy_get_parents($value->tid) ) {
$model=$key;
}
else {
$make=$key;
}
}
$additions = new stdClass();
$additions->make = $make;
$additions->model = $model;
return $additions;
}
/**
* Implementation of hook_view().
*
* This is a typical implementation that simply runs the node text through
* the output filters.
*
* Do I need this?
*/
function node_vehicle_view($node, $teaser = FALSE, $page = FALSE) {
$node = node_prepare($node, $teaser);
return $node;
}
/**
* Implementation of hook_theme().
*
* Tell Drupal about theme functions and their arguments.
*/
function node_vehicle_theme() {
return array(
'makemodel' => array(
'arguments' => array('element'),
),
);
}