View source
<?php
function resource_conflict_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
switch ($op) {
case 'validate':
$type = $node->type;
if (!variable_get('rc_type_' . $type, FALSE)) {
break;
}
$date_field = variable_get('rc_date_field_' . $type, FALSE);
$overlapping_node_ids = array();
if (strpos($date_field, 'field_', 0) === 0) {
$start = $node->{$date_field}[0]['value'];
$end = $node->{$date_field}[0]['value2'];
if (!empty($start) && !empty($end)) {
$overlapping_node_ids = _resource_conflict_overlaps_from_date($start, $end);
}
else {
_resource_conflict_disable($type);
}
}
if (!empty($node->event_start)) {
$tmp = _resource_conflict_overlaps_from_event($node->event_start, $node->event_end);
$overlapping_node_ids = array_unique(array_merge($overlapping_node_ids, $tmp));
}
$conflicting_nodes = array();
foreach ($overlapping_node_ids as $nid) {
if ($nid != $node->nid) {
$conflicting_nodes[$nid] = node_load($nid);
}
}
_resource_conflict_display_conflict_errors($node, $conflicting_nodes);
break;
}
}
function _resource_conflict_display_conflict_errors($node, $conflicting_nodes) {
$our_demands = _resource_conflict_get_node_resource_demand($node);
foreach ($conflicting_nodes as $conflicting_node) {
$other_demands = _resource_conflict_get_node_resource_demand($conflicting_node);
$conflicting_resources = array();
foreach ($our_demands as $our_demand => $dummy) {
if (isset($other_demands[$our_demand])) {
$conflicting_resources[$our_demand] = node_load($our_demand);
}
}
foreach ($conflicting_resources as $conflicting_resource) {
$date_field = variable_get('rc_date_field_' . $conflicting_node->type, FALSE);
if (strpos($date_field, 'field_', 0) === 0) {
$type = DATE_ISO;
if (!date_is_valid($date_start, DATE_ISO)) {
$type = DATE_DATETIME;
}
$start = format_date(date_convert($conflicting_node->{$date_field}[0]['value'], $type, DATE_UNIX));
$end = format_date(date_convert($conflicting_node->{$date_field}[0]['value2'], $type, DATE_UNIX));
}
else {
$start = format_date($conflicting_node->event_start);
$end = format_date($conflicting_node->event_end);
}
$error = t('There is a resource conflict: <a href="@resource-url">%resource</a> is currently booked for <a href="@booker-url">%booker</a> from %start to %end. Please choose a different time or a different resource.', array(
'@booker-url' => url('node/' . $conflicting_node->nid),
'%booker' => $conflicting_node->title,
'@resource-url' => url('node/' . $conflicting_resource->nid),
'%resource' => $conflicting_resource->title,
'%start' => $start,
'%end' => $end,
));
$conflict_id = $conflicting_resource->nid . '_' . $conflicting_node->nid;
form_set_error($conflict_id, $error);
}
}
}
function resource_conflict_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'node_type_form') {
$requirements = array();
$type = isset($form['old_type']) && isset($form['old_type']['#value']) ? $form['old_type']['#value'] : NULL;
$form['resource_conflict_set'] = array(
'#type' => 'fieldset',
'#title' => t('Resource Conflict'),
'#collapsible' => TRUE,
);
if ($type == NULL) {
$form['resource_conflict_set']['rc_info'] = array(
'#prefix' => '<p>',
'#suffix' => '</p>',
'#value' => t('To set up this content type for conflict checking, first event-enable the type, or add a Date CCK field with required start and end dates. Then, add at least one Node Reference field linked to the content type of items you would like to be able to book. When all of the conditions have been met, this section will be enabled for configuration.'),
);
return;
}
$date_fields = array();
if ($type != NULL) {
$type_info = content_types($type);
$fields = $type_info['fields'];
foreach ($fields as $field) {
if ($field['type'] == 'nodereference') {
$nodereference_fields[$field['field_name']] = $field['widget']['label'];
}
elseif (($field['type'] == 'date' || $field['type'] == 'datetime') && $field['todate'] == 'required' && $field['required']) {
$date_fields[$field['field_name']] = $field['widget']['label'];
}
}
}
if (empty($nodereference_fields)) {
$requirements['nodereference'] = t('At least one Node Reference field must be added to this content type.');
}
if (module_exists('event')) {
$event_enabled = event_enabled_state($type) == "all" || event_enabled_state($type) == "solo";
}
else {
$event_enabled = FALSE;
}
if ($event_enabled) {
$date_fields += array(
'event' => t('Use Event Field from the Event Module'),
);
}
if (empty($date_fields) && !$event_enabled) {
if (module_exists('event')) {
$requirements['event'] = t('This content type is not event enabled. Please event-enable this content type if you wish to use Resource Conflict with the Event module.');
}
else {
$requirements['event'] = t('This content type is not event enabled. Please install the Event module if you wish to use Resource Conflict with the Event module.');
}
$requirements['date_api'] = t('This content type does not contain any suitable Date fields. Please add at least one Date field with required start and end dates if you wish to use Resource Conflict with the Date module.');
}
if (!empty($requirements)) {
_resource_conflict_disable($type, TRUE);
$form['resource_conflict_set']['requirements'] = array(
'#prefix' => '<p>' . t('The following requirements for Resource Conflict have not been met:') . '</p><ol>',
'#suffix' => '</ol>',
'#weight' => -10,
);
foreach ($requirements as $component => $error) {
$form['resource_conflict_set']['requirements'][$component] = array(
'#prefix' => '<li>',
'#suffix' => '</li>',
'#value' => $error,
);
}
}
else {
$form['resource_conflict_set']['rc_type'] = array(
'#type' => 'checkbox',
'#title' => t('Enable resource conflict checking for this content type'),
'#default_value' => variable_get('rc_type_' . $type, 0),
'#weight' => -8,
);
$form['resource_conflict_set']['rc_date_field'] = array(
'#type' => 'select',
'#title' => t('Field to use as the date for conflict checks'),
'#options' => $date_fields,
'#multiple' => FALSE,
'#default_value' => variable_get('rc_date_field_' . $type, FALSE),
'#description' => t("Select the date field to use to check for resource conflicts."),
);
$form['resource_conflict_set']['rc_reference_fields'] = array(
'#type' => 'checkboxes',
'#title' => t('Fields to check for conflicts'),
'#options' => $nodereference_fields,
'#default_value' => variable_get('rc_reference_fields_' . $type, array()),
'#description' => t("Select the resources which can't be booked at the same time."),
);
}
$form['#validate'][] = 'resource_conflict_form_validate';
$form['#submit'][] = 'resource_conflict_form_submit';
}
}
function resource_conflict_form_validate($form, &$form_state) {
if ($form_state['values']['form_id'] == 'node_type_form') {
if ($form_state['values']['rc_type']) {
$resource_selected = FALSE;
foreach ($form_state['values']['rc_reference_fields'] as $field) {
if ($field) {
$resource_selected = TRUE;
break;
}
}
if (!$resource_selected) {
form_set_error('rc_reference_fields', t("At least one resource field must be set if conflict handling is enabled."));
}
}
}
}
function resource_conflict_form_submit($form, &$form_state) {
$type = $form_state['values']['type'];
$old_type = $form_state['values']['old_type'];
$conflict_types = variable_get("rc_types", array());
if (!empty($old_type)) {
$key = array_search($old_type, $conflict_types);
unset($conflict_types[$key]);
}
if ($form_state['values']['rc_type']) {
$conflict_types[] = $type;
}
variable_set("rc_types", $conflict_types);
}
function _resource_conflict_get_conflict_enabled_types() {
$conflict_types = variable_get("rc_types", array());
return $conflict_types;
}
function _resource_conflict_get_node_resource_demand($node) {
$type = $node->type;
$reference_fields = variable_get('rc_reference_fields_' . $type, array());
$demand = array();
foreach ($reference_fields as $reference_field) {
$references = $node->{$reference_field};
foreach ($references as $reference) {
if (is_array($reference['nid'])) {
form_set_error('no_resources', t('No bookable resources have been created. Please create resources to book before attempting to create a resource booking.'));
}
else {
if (is_numeric($reference['nid'])) {
$demand[$reference['nid']] = TRUE;
}
}
}
}
return $demand;
}
function _resource_conflict_overlaps_from_date($date_start, $date_end) {
$type = DATE_ISO;
if (!date_is_valid($date_start, DATE_ISO)) {
$type = DATE_DATETIME;
}
$start = date_make_date($date_start, 'GMT', $type);
$end = date_make_date($date_end, 'GMT', $type);
return _resource_conflict_get_overlaps($start, $end);
}
function _resource_conflict_overlaps_from_event($event_start, $event_end) {
$start = date_make_date($event_start, 'GMT', DATE_UNIX);
$end = date_make_date($event_end, 'GMT', DATE_UNIX);
return _resource_conflict_get_overlaps($start, $end);
}
function _resource_conflict_get_overlaps($start, $end) {
$date_start = date_convert($start, DATE_OBJECT, DATE_ISO);
$date_end = date_convert($end, DATE_OBJECT, DATE_ISO);
$event_start = date_convert($start, DATE_OBJECT, DATE_UNIX);
$event_end = date_convert($end, DATE_OBJECT, DATE_UNIX);
$rows = array();
$conflict_types = _resource_conflict_get_conflict_enabled_types();
foreach ($conflict_types as $type) {
$date_field = variable_get('rc_date_field_' . $type, FALSE);
if (strpos($date_field, 'field_', 0) === 0) {
$date_db_info = content_database_info(content_fields($date_field));
$date_table = '{' . $date_db_info['table'] . '}';
$start_field_name = $date_db_info['columns']['value']['column'];
$end_field_name = $date_db_info['columns']['value2']['column'];
$query = "SELECT DISTINCT {node}.nid FROM {node} INNER JOIN {$date_table} date_table ON {node}.vid = date_table.vid\n WHERE('%s' >= date_table.{$start_field_name} AND '%s' < date_table.{$end_field_name})\n OR('%s' > date_table.{$start_field_name} AND '%s' <= date_table.{$end_field_name})\n OR('%s' <= date_table.{$start_field_name} AND '%s' >= date_table.{$end_field_name})";
$result = db_query($query, $date_start, $date_start, $date_end, $date_end, $date_start, $date_end);
while ($row = db_fetch_array($result)) {
$rows[] = $row['nid'];
}
}
elseif ($date_field == 'event') {
$query = "SELECT DISTINCT nid FROM {event} WHERE (%d >= event_start AND %d < event_end)\n OR (%d > event_start AND %d <= event_end)\n OR (%d <= event_start AND %d >= event_end)";
$result = db_query($query, $event_start, $event_start, $event_end, $event_end, $event_start, $event_end);
while ($row = db_fetch_array($result)) {
$rows[] = $row['nid'];
}
}
}
return array_unique($rows);
}
function _resource_conflict_disable($type, $display = FALSE) {
if (variable_get('rc_type_' . $type, FALSE)) {
variable_del('rc_type_' . $type);
$msg = t('Resource Conflict has been disabled for the %type content type as the requirements for it are no longer met.', array(
'%type' => $type,
));
if ($display) {
drupal_set_message($msg, 'Resource Conflict');
}
watchdog('rsrc conflict', $msg, WATCHDOG_WARNING);
}
}
if (!function_exists('date_show_value')) {
function date_show_value($date, $type = 'db', $format = DATE_ISO) {
if ($format == DATE_UNIX) {
return $date->{$type}->timestamp;
}
else {
return $date->{$type}->iso;
}
}
}