relation_class.module in Subform 5
CRUD, and manage relation_classes and relation_class lists
File
relation_class.moduleView source
<?php
/**
* @file
* CRUD, and manage relation_classes and relation_class lists
*/
/**
* Implementation of hook_help()
* Display help text for the relation_class module
*/
function relation_class_help($section) {
switch ($section) {
case 'admin/help#relation_class':
$o .= '<p>' . t('CRUD, and manage relation_classes and relation_class lists.') . '</p>';
return $o;
case 'node/add#relation_class':
return t('Defines a type of relationship that can exist between nodes.');
}
}
/**
* Implementation of hook_perm().
* Define the permissions this module uses
*/
function relation_class_perm() {
return array(
'create relation_class items',
'manage relation_class items',
);
}
/**
* Implementation of hook_access().
*/
function relation_class_access($op, $node) {
global $user;
if ($op == 'create') {
return user_access('create relation_class items');
}
if ($op == 'update' || $op == 'delete') {
if (user_access('manage relation_class items')) {
return TRUE;
}
}
}
/**
* Implementation of hook_menu().
*/
function relation_class_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'title' => t('relation_class'),
'path' => 'node/add/relation_class',
'access' => user_access('create relation_class items'),
);
$items[] = array(
'title' => t('manage relation classes'),
'path' => 'node/manage/relation_class',
'access' => user_access('manage relation_class items'),
'callback' => '_manage_relation_classes',
);
}
return $items;
}
/**
* Implementation of hook_node_info().
* Define the node type
*/
function relation_class_node_info() {
return array(
'relation_class' => array(
'name' => t('relation class'),
'base' => 'relation_class',
'module' => 'relation_class',
),
);
}
/**
* hook_form
*/
function relation_class_form(&$node) {
drupal_set_html_head(theme('stylesheet_import', base_path() . drupal_get_path('module', 'subform') . '/subform.css'), "module");
drupal_set_html_head(theme('stylesheet_import', base_path() . drupal_get_path('module', 'subform') . '/relation_class.css'), "module");
$form = array(
'title' => array(
'#type' => 'textfield',
'#title' => t('Title'),
'#required' => TRUE,
'#default_value' => $node->title,
'#weight' => -5,
),
'sides' => array(
'#type' => 'fapi_table',
'rows' => array(
array(
// first row
array(
// first cell
'left_node_type' => array(
'#type' => 'select',
'#title' => t('Node Type'),
'#default_value' => $node->left_node_type,
'#options' => node_get_types(),
'#required' => TRUE,
),
),
array(
// second cell
'right_node_type' => array(
'#type' => 'select',
'#title' => t('Node Type'),
'#default_value' => $node->right_node_type,
'#options' => node_get_types(),
'#required' => TRUE,
),
),
),
array(
// second row
array(
// first cell
'left_node_cardinality' => array(
'#type' => 'textfield',
'#title' => t('Cardinality'),
'#default_value' => $node->left_node_cardinality,
'#required' => TRUE,
),
),
array(
// second cell
'right_node_cardinality' => array(
'#type' => 'textfield',
'#title' => t('Cardinality'),
'#default_value' => $node->right_node_cardinality,
'#required' => TRUE,
),
),
),
array(
// third row
array(
// first cell
'unique_instances' => array(
'#type' => 'checkbox',
'#title' => 'Prevent duplicate relation instances?',
'#default_value' => isset($node->unique_instances) ? $node->unique_instances : true,
),
),
array(),
),
),
),
);
return $form;
}
/**
* Implementation of hook_view, add our node specific information
* @param node object to display
* @param boolean is this a teaser or full node?
* @param boolean is this displaying on its own page
*/
function relation_class_view(&$node, $teaser = FALSE, $page = FALSE) {
$node = node_prepare($node, $teaser);
$node->body = theme('relation_class_view', $node);
}
/**
* Theme function to display additional node data
* @param node to display
* @return HTML string with additional node information
*/
function theme_relation_class_view($node) {
$output = '<div class="relation_class_view">';
$output .= "<pre>{$node->title} : {$node->left_node_type}({$node->left_node_cardinality}) <-> {$node->right_node_type}({$node->right_node_cardinality})" . ($node->unique_instances ? "Unique" : "") . "</pre>";
$output .= '</div>';
return $output;
}
/**
* Validate our forms
* @param string form id
* @param array form values
*/
function relation_class_validate($form_id, $form_values) {
// drupal_set_message( '<pre>' . print_r( $form_values, true ) . '</pre>' );
if (!is_numeric($form_values['sides']['rows'][1][0]['left_node_cardinality']['#value'])) {
form_set_error('left_node_cardinality', t('Left Node Cardinality must be an integer.'));
}
else {
$form_values['sides']['rows'][1][0]['left_node_cardinality']['#value'] = intval($form_values['left_node_cardinality']['#value']);
}
if (!is_numeric($form_values['sides']['rows'][1][1]['right_node_cardinality']['#value'])) {
form_set_error('right_node_cardinality', t('Right Node Cardinality must be an integer.'));
}
else {
$form_values['sides']['rows'][1][1]['right_node_cardinality']['#value'] = intval($form_values['left_node_cardinality']['#value']);
}
}
function relation_class_insert($node) {
db_query("\n INSERT INTO\n {relation_class}\n (nid, vid, left_node_type, left_node_cardinality, right_node_type, right_node_cardinality, unique_instances)\n VALUES\n ({$node->nid}, {$node->vid}, '{$node->left_node_type}', {$node->left_node_cardinality}, '{$node->right_node_type}', {$node->right_node_cardinality}, {$node->unique_instances})");
}
function relation_class_list() {
$relation_class_results = db_query("SELECT nid, title FROM {node} WHERE type = 'relation_class' ORDER BY title");
$relation_classes = array();
while ($relation_class = db_fetch_object($relation_class_results)) {
$relation_classes[$relation_class->nid] = $relation_class->title;
}
return $relation_classes;
}
function relation_class_extended_list() {
$relation_class_results = db_query("SELECT {node}.nid, {node}.title, {relation_class}.left_node_type, {relation_class}.left_node_cardinality, {relation_class}.right_node_type, {relation_class}.right_node_cardinality FROM {node} INNER JOIN {relation_class} ON {node}.nid = {relation_class}.nid AND {node}.vid = {relation_class}.vid WHERE type = 'relation_class' ORDER BY title");
$relation_classes = array();
while ($relation_class = db_fetch_object($relation_class_results)) {
$relation_classes[$relation_class->nid] = "{$relation_class->title} : {$relation_class->left_node_type}({$relation_class->left_node_cardinality}) <-> {$relation_class->right_node_type}({$relation_class->right_node_cardinality})";
}
return $relation_classes;
}
/**
* Implemenation of hook_load
* @param node object to load additional information for
* @return object with todo fields
*/
function relation_class_load($node) {
return db_fetch_object(db_query("SELECT left_node_type, left_node_cardinality, right_node_type, right_node_cardinality, unique_instances FROM {relation_class} WHERE nid = %d AND vid = %d", $node->nid, $node->vid));
}
/**
* hook_update, saves changes
* @param node object
*/
function relation_class_update($node) {
db_query("\n UPDATE\n {relation_class}\n SET\n left_node_type = '{$node->left_node_type}',\n left_node_cardinality = {$node->left_node_cardinality},\n right_node_type = '{$node->right_node_type}',\n right_node_cardinality = {$node->right_node_cardinality},\n unique_instances = {$node->unique_instances}\n WHERE\n nid = {$node->nid}\n AND\n vid = {$node->vid}");
}
function _manage_relation_classes() {
drupal_set_html_head(theme('stylesheet_import', base_path() . drupal_get_path('module', 'subform') . '/subform.css'), "module");
drupal_set_html_head(theme('stylesheet_import', base_path() . drupal_get_path('module', 'subform') . '/manage_relation_classes.css'), "module");
$relation_class_results = db_query("\n SELECT\n *\n FROM\n {relation_class}\n INNER JOIN\n {node}\n ON\n {relation_class}.nid = {node}.nid\n AND\n {relation_class}.vid = {node}.vid\n ");
drupal_add_js(drupal_get_path('module', 'subform') . '/iframe_resize.js', "module");
$output = "";
while ($relation_class = db_fetch_object($relation_class_results)) {
$output[] = "\n<div class='iframe_div'><iframe\n class='subform_iframe'\n src='" . check_url(url("subform/{$relation_class->nid}/edit", NULL, NULL, TRUE)) . "'\n onload='resizeIFrame(this);'>\n</IFRAME></div>";
}
$new = "\n\n<script>\n\nfunction newRelationClass() {\n\n var table = document.getElementById('relation_classes_table');\n\n var row = table.insertRow( table.rows.length );\n var cell = row.insertCell(0);\n cell.innerHTML += '<div class=\\'iframe_div\\'><iframe class=\\'subform_iframe\\' src=\\'" . check_url(url('subform/add/relation_class', NULL, NULL, TRUE)) . "\\' onload=\\'resizeIFrame(this);\\'></iframe></div>';\n\n}\n\n</script>\n<br />\n<a href='#' onClick='newRelationClass(); return false;'>New</a>\n\n";
$output = "<table width=100% id=\"relation_classes_table\"><tr><td>" . ($output ? implode("</td></tr><tr><td>", $output) : "") . "</td></tr></table>{$new}";
$form = array(
'relation_classes' => array(
'#type' => 'markup',
'#value' => $output,
),
);
return drupal_get_form('_manage_relation_classes', $form);
}
function relation_instance_load($relation_instance_id) {
return db_fetch_object(db_query("SELECT * FROM {relation_instance} WHERE id = %d", $relation_instance_id));
}
function relation_instance_delete($relation_instance_id) {
db_query("DELETE FROM {relation_instance} WHERE id = %d", $relation_instance_id);
return "deleted";
}
function relation_instance_update($old_parent_node, $parent_node) {
db_query("\n UPDATE\n {relation_instance}\n SET\n left_node = {$parent_node}\n WHERE left_node = {$old_parent_node}");
db_query("\n UPDATE\n {relation_instance}\n SET\n right_node = {$parent_node}\n WHERE right_node = {$old_parent_node}");
}
function relation_instance_insert($node) {
relation_instance_trim_stale();
$relation_class = node_load($node->relation_class);
if ($relation_class->unique_instances) {
if ($id = db_result(db_query("SELECT id FROM {relation_instance} WHERE relation_class = %d AND left_node = %d AND right_node = %d", $node->relation_class, $node->left_node, $node->right_node))) {
return $id;
}
}
db_query("\n INSERT INTO\n {relation_instance}\n (relation_class, left_node, right_node, timestamp)\n VALUES\n ({$node->relation_class}, {$node->left_node}, {$node->right_node}, " . strtotime("now") . ")");
return db_result(db_query("SELECT LAST_INSERT_ID()"));
}
function relation_instance_selectables_query($relation_class, $child_side, $parent_node) {
$relation_class_node = node_load($relation_class);
$child_side_node = $child_side . "_node";
$child_side_node_type = $child_side . "_node_type";
$child_side_node_type = $relation_class_node->{$child_side_node_type};
$child_side_cardinality = $child_side . "_node_cardinality";
$child_side_cardinality = $relation_class_node->{$child_side_cardinality};
$parent_side = $child_side == "left" ? "right" : "left";
$parent_side_node = $parent_side . "_node";
$duplicate_relation_cost = $relation_class_node->unique_instances ? $child_side_cardinality : 1;
$sql = "\nSELECT\n nid, SUM(related) as related_count\nFROM\n(\n SELECT\n nid, IF(relation_class IS NULL, 0, IF({$parent_side_node} <= 0, IF({$parent_side_node} = {$parent_node}, {$duplicate_relation_cost}, 0), IF({$parent_side_node} = {$parent_node}, {$duplicate_relation_cost}, 1))) as related\n FROM\n node\n LEFT JOIN\n relation_instance ON node.nid = relation_instance.{$child_side_node}\n WHERE\n node.type = '{$child_side_node_type}'\n AND\n (\n relation_class IS NULL\n OR\n relation_class = {$relation_class}\n )\n) as possibilities\nGROUP BY\n nid\nHAVING\n related_count < {$child_side_cardinality}\n ";
// drupal_set_message( $sql );
return $sql;
}
function relation_instance_used_slots($relation_class, $parent_side_node, $child_side_node, $parent_node) {
return db_result(db_query("SELECT\n COUNT({$child_side_node})\n FROM\n {relation_instance}\n WHERE\n relation_class = %d\n AND\n {$parent_side_node} = %d", $relation_class, $parent_node));
}
function relation_instance_trim_stale() {
db_query("DELETE\n FROM\n {relation_instance}\n WHERE\n (left_node < 0\n OR\n right_node < 0)\n AND\n timestamp <= %d", strtotime("now") - 24 * 60 * 60);
}