/[drupal]/contributions/modules/resource_conflict/resource_conflict.module
ViewVC logotype

Contents of /contributions/modules/resource_conflict/resource_conflict.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Wed Aug 5 16:01:53 2009 UTC (3 months, 3 weeks ago) by deviantintegral
Branch: MAIN
CVS Tags: DRUPAL-6--2-0-RC1, DRUPAL-6--2-0, HEAD
Changes since 1.4: +2 -2 lines
File MIME type: text/x-php
#518844: Data too long for column 'type'.
1 <?php
2 // $Id: resource_conflict.module,v 1.4 2009/08/05 15:31:26 deviantintegral Exp $
3 //VIM setup ex: et sw=2 ts=2 syntax=php
4
5 /**
6 * Implementation of hook_nodeapi
7 *
8 * Determine if a required resource is currently booked.
9 */
10 function resource_conflict_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
11 switch ($op) {
12 case 'validate':
13 $type = $node->type;
14 if (!variable_get('rc_type_' . $type, FALSE)) {
15 // Conflict handling is not enabled for this node.
16 break;
17 }
18
19 // Find the date field to use for time overlapping_node_ids detection.
20 $date_field = variable_get('rc_date_field_' . $type, FALSE);
21
22 $overlapping_node_ids = array();
23
24 if (strpos($date_field, 'field_', 0) === 0) {
25 // Get the start and end Date of the current node
26 $start = $node->{$date_field}[0]['value'];
27 $end = $node->{$date_field}[0]['value2'];
28
29 // Get all conflicting Date nodes
30 if (!empty($start) && !empty($end)) {
31 $overlapping_node_ids = _resource_conflict_overlaps_from_date($start, $end);
32 }
33 else {
34 // If we got here, someone broke the requirements, so turn off
35 // resource conflict for this type and notify an admin
36 _resource_conflict_disable($type);
37 }
38 }
39 if (!empty($node->event_start)) {
40 // Get all overlapping events
41 $tmp = _resource_conflict_overlaps_from_event($node->event_start, $node->event_end);
42 $overlapping_node_ids = array_unique(array_merge($overlapping_node_ids, $tmp));
43 }
44
45 // Load conflicting nodes
46 $conflicting_nodes = array();
47 foreach ($overlapping_node_ids as $nid) {
48 // Don't have the node conflict with itself
49 if ($nid != $node->nid) {
50 $conflicting_nodes[$nid] = node_load($nid);
51 }
52 }
53
54 // Display conflict errors
55 _resource_conflict_display_conflict_errors($node, $conflicting_nodes);
56 break;
57 }
58 }
59
60
61 /**
62 * Compare our demand to the demand of overlapping nodes
63 * and display errors for the intersections
64 *
65 * @param $node the currently validating node
66 * @param $conflicting_nodes array of nodes that overlap with this node
67 */
68 function _resource_conflict_display_conflict_errors($node, $conflicting_nodes) {
69 $our_demands = _resource_conflict_get_node_resource_demand($node);
70 foreach ($conflicting_nodes as $conflicting_node) {
71 $other_demands = _resource_conflict_get_node_resource_demand($conflicting_node);
72
73 // select the resources that both this node and the other node demands
74 $conflicting_resources = array();
75 foreach ($our_demands as $our_demand => $dummy) {
76 if (isset($other_demands[$our_demand])) {
77 $conflicting_resources[$our_demand] = node_load($our_demand);
78 }
79 }
80
81 // display the error for each conflict
82 foreach ($conflicting_resources as $conflicting_resource) {
83 $date_field = variable_get('rc_date_field_'. $conflicting_node->type, FALSE);
84 if (strpos($date_field, 'field_', 0) === 0) {
85 $start = format_date(date_convert($conflicting_node->{$date_field}[0]['value'], DATE_ISO, DATE_UNIX));
86 $end = format_date(date_convert($conflicting_node->{$date_field}[0]['value2'], DATE_ISO, DATE_UNIX));
87 }
88 else {
89 $start = format_date($conflicting_node->event_start);
90 $end = format_date($conflicting_node->event_end);
91 }
92
93 $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.',
94 array(
95 '@booker-url' => url('node/'. $conflicting_node->nid),
96 '%booker' => $conflicting_node->title,
97 '@resource-url' => url('node/'. $conflicting_resource->nid),
98 '%resource' => $conflicting_resource->title,
99 '%start' => $start,
100 '%end' => $end,
101 )
102 );
103
104 // This is a bit of a hack, but there's no way with FAPI to have
105 // multiple form errors on the same field. So, we just pass in
106 // a bogus (but unique) ID for each error message, to ensure
107 // that all conflicts are reported simultaneously. We use the
108 // nid of the conflicting resource (thing) appended with the nid
109 // of the conflicting node (reservation event).
110 $conflict_id = $conflicting_resource->nid . '_' . $conflicting_node->nid;
111 form_set_error($conflict_id, $error);
112 }
113 }
114 }
115
116 /**
117 * Implementation of hook_form_alter
118 */
119 function resource_conflict_form_alter(&$form, $form_state, $form_id) {
120 if ($form_id == 'node_type_form') {
121 $requirements = array();
122
123 $type = (isset($form['old_type']) && isset($form['old_type']['#value'])) ? $form['old_type']['#value'] : NULL;
124
125 $form['resource_conflict_set'] = array(
126 '#type' => 'fieldset',
127 '#title' => t('Resource Conflict'),
128 '#collapsible' => TRUE,
129 );
130
131 // The user is adding a new content type
132 if ($type == NULL) {
133 $form['resource_conflict_set']['rc_info'] = array(
134 '#prefix' => '<p>',
135 '#suffix' => '</p>',
136 '#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.'),
137 );
138 return;
139 }
140
141 $date_fields = array();
142 if ($type != NULL) {
143 $type_info = content_types($type);
144 $fields = $type_info['fields'];
145
146 foreach ($fields as $field) {
147 if ($field['type'] == 'nodereference') {
148 $nodereference_fields[$field['field_name']] = $field['widget']['label'];
149 }
150 elseif ($field['type'] == 'date' && $field['todate'] == 'required' && $field['required']) {
151 $date_fields[$field['field_name']] = $field['widget']['label'];
152 }
153 }
154 }
155
156 if (empty($nodereference_fields)) {
157 $requirements['nodereference'] = t('At least one Node Reference field must be added to this content type.');
158 }
159
160 if (module_exists('event')) {
161 $event_enabled = (event_enabled_state($type) == "all" || event_enabled_state($type) == "solo");
162 }
163 else {
164 $event_enabled = FALSE;
165 }
166
167 // If we are event enabled, allow the selection of the Event field.
168 if ($event_enabled) {
169 $date_fields += array('event' => t('Use Event Field from the Event Module'));
170 }
171
172 if (empty($date_fields) && !$event_enabled) {
173 if (module_exists('event')) {
174 $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.');
175 }
176 else {
177 $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.');
178 }
179
180 $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.');
181 }
182
183 if (!empty($requirements)) {
184 _resource_conflict_disable($type, TRUE);
185
186 $form['resource_conflict_set']['requirements'] = array(
187 '#prefix' => '<p>' . t('The following requirements for Resource Conflict have not been met:') . '</p><ol>',
188 '#suffix' => '</ol>',
189 '#weight' => -10,
190 );
191 foreach ($requirements as $component => $error) {
192 $form['resource_conflict_set']['requirements'][$component] = array(
193 '#prefix' => '<li>',
194 '#suffix' => '</li>',
195 '#value' => $error,
196 );
197 }
198 }
199 else {
200 $form['resource_conflict_set']['rc_type'] = array(
201 '#type' => 'checkbox',
202 '#title' => t('Enable resource conflict checking for this content type'),
203 '#default_value' => variable_get('rc_type_' . $type, 0),
204 '#weight' => -8,
205 );
206
207 $form['resource_conflict_set']['rc_date_field'] = array(
208 '#type' => 'select',
209 '#title' => t('Field to use as the date for conflict checks'),
210 '#options' => $date_fields,
211 '#multiple' => FALSE,
212 '#default_value' => variable_get('rc_date_field_' . $type, FALSE),
213 '#description' => t("Select the date field to use to check for resource conflicts."),
214 );
215
216 $form['resource_conflict_set']['rc_reference_fields'] = array(
217 '#type' => 'checkboxes',
218 '#title' => t('Fields to check for conflicts'),
219 '#options' => $nodereference_fields,
220 '#default_value' => variable_get('rc_reference_fields_' . $type, array()),
221 '#description' => t("Select the resources which can't be booked at the same time."),
222 );
223 }
224
225 //set custom validation and submit callbacks
226 $form['#validate'][] = 'resource_conflict_form_validate';
227 $form['#submit'][] = 'resource_conflict_form_submit';
228 }
229 }
230
231 /**
232 * Validate the node_type_form
233 */
234 function resource_conflict_form_validate($form, &$form_state) {
235 if ($form_state['values']['form_id'] == 'node_type_form') {
236 if ($form_state['values']['rc_type']) {
237 $resource_selected = FALSE;
238 foreach ($form_state['values']['rc_reference_fields'] as $field) {
239 if ($field) {
240 $resource_selected = TRUE;
241 break;
242 }
243 }
244 if (!$resource_selected) {
245 form_set_error('rc_reference_fields', t("At least one resource field must be set if conflict handling is enabled."));
246 }
247 }
248 }
249 }
250
251 /**
252 * Submit the node_type_form
253 */
254 function resource_conflict_form_submit($form, &$form_state) {
255 $type = $form_state['values']['type'];
256 $old_type = $form_state['values']['old_type'];
257 $conflict_types = variable_get("rc_types", array());
258
259 //unset old entry
260 if (!empty($old_type)) {
261 $key = array_search($old_type, $conflict_types);
262 unset($conflict_types[$key]);
263 }
264
265 //make new entry if this type is conflict handled
266 if ($form_state['values']['rc_type']) {
267 $conflict_types[] = $type;
268 }
269
270 variable_set("rc_types", $conflict_types);
271 }
272
273 /**
274 * Get the conflict enabled types
275 *
276 * @return
277 * An array of type names
278 */
279 function _resource_conflict_get_conflict_enabled_types() {
280 $conflict_types = variable_get("rc_types", array());
281 return $conflict_types;
282 }
283
284 /**
285 * Get a conflict enabled node's resource demand
286 *
287 * @param $node
288 * The node which resurce demand will be returned
289 * @return
290 * An array with keys of the node ID's, values of true
291 */
292 function _resource_conflict_get_node_resource_demand($node) {
293 $type = $node->type;
294 $reference_fields = variable_get('rc_reference_fields_' . $type, array());
295
296 $demand = array();
297 foreach ($reference_fields as $reference_field) {
298 $references = $node->{$reference_field};
299 foreach ($references as $reference) {
300 /**
301 * Check to see if any referencable resources exist. If they don't, file
302 * an error. This only matters when the nodereference field is set to
303 * required, otherwise this code doesn't get called at all. We have to
304 * file the error against the fake 'no_resources' element as CCK files
305 * it's own "Illegal choice" error before we get called.
306 */
307 if (is_array($reference['nid'])) {
308 form_set_error('no_resources', t('No bookable resources have been created. Please create resources to book before attempting to create a resource booking.'));
309 }
310 else if (is_numeric($reference['nid'])){
311 $demand[$reference['nid']] = TRUE;
312 }
313 }
314 }
315 return $demand;
316 }
317
318 /**
319 * Determine if any nodes conflict between the specified dates using Date API.
320 *
321 * @param $date_start
322 * The start date of the date to check
323 * @param $date_end
324 * The end date of the date to check.
325 * @return
326 * An array of node ID's
327 */
328 function _resource_conflict_overlaps_from_date($date_start, $date_end) {
329 $start = date_make_date($date_start, 'GMT', DATE_ISO);
330 $end = date_make_date($date_end, 'GMT', DATE_ISO);
331 return _resource_conflict_get_overlaps($start, $end);
332 }
333
334 /**
335 * Determine if any nodes conflict between the specified dates using Event.
336 *
337 * @param $event_start
338 * The start date of the event to check
339 * @param $event_end
340 * The end date of the event to check.
341 * @return
342 * An array of node ID's
343 */
344 function _resource_conflict_overlaps_from_event($event_start, $event_end) {
345 $start = date_make_date($event_start, 'GMT', DATE_UNIX);
346 $end = date_make_date($event_end, 'GMT', DATE_UNIX);
347 return _resource_conflict_get_overlaps($start, $end);
348 }
349
350 /**
351 * Determine if any conflict enabled nodes overlap the specified times
352 *
353 * 1. $start is within the event time
354 * 2. $end end is within the event time
355 * 3. The event encompasses $start and $end
356 * 4. Allow the end of one event to occur at the start of the next
357 *
358 * @param $start
359 * The start time of events to search as dateAPI object
360 * @param $end
361 * The end time of events to search as dateAPI object
362 * @return
363 * An array of node ID's
364 */
365 function _resource_conflict_get_overlaps($start, $end) {
366 $date_start = date_convert($start, DATE_OBJECT, DATE_ISO);
367 $date_end = date_convert($end, DATE_OBJECT, DATE_ISO);
368 $event_start = date_convert($start, DATE_OBJECT, DATE_UNIX);
369 $event_end = date_convert($end, DATE_OBJECT, DATE_UNIX);
370
371 $rows = array();
372 $conflict_types = _resource_conflict_get_conflict_enabled_types();
373
374 foreach ($conflict_types as $type) {
375 $date_field = variable_get('rc_date_field_' . $type, FALSE);
376
377 if(strpos($date_field, 'field_', 0) === 0) {
378 $date_db_info = content_database_info(content_fields($date_field));
379 $date_table = '{' . $date_db_info['table'] . '}';
380
381 $start_field_name = $date_db_info['columns']['value']['column'];
382 $end_field_name = $date_db_info['columns']['value2']['column'];
383
384 $query = "SELECT DISTINCT nid FROM $date_table
385 WHERE('%s' >= $start_field_name AND '%s' < $end_field_name)
386 OR('%s' > $start_field_name AND '%s' <= $end_field_name)
387 OR('%s' <= $start_field_name AND '%s' >= $end_field_name)";
388
389 $result = db_query($query, $date_start, $date_start, $date_end, $date_end, $date_start, $date_end);
390
391 // Create an array of all of the results
392 while ($row = db_fetch_array($result)) {
393 $rows[] = $row['nid'];
394 }
395 }
396 elseif ($date_field == 'event') { //event enabled
397 $query = "SELECT DISTINCT nid FROM {event} WHERE (%d >= event_start AND %d < event_end)
398 OR (%d > event_start AND %d <= event_end)
399 OR (%d <= event_start AND %d >= event_end)";
400 $result = db_query($query, $event_start, $event_start, $event_end, $event_end, $event_start, $event_end);
401
402 // Create an array of all of the results
403 while($row = db_fetch_array($result)) {
404 $rows[] = $row['nid'];
405 }
406 }
407 }
408 return array_unique($rows);
409 }
410
411 /**
412 * Disable resource conflict for a type, optionally notifying the user. A
413 * message is always logged in the Drupal log. If the content type is not
414 * conflict-enabled, nothing is changed.
415 *
416 * @param $type
417 * The content type to disable.
418 *
419 * @param $display
420 * If TRUE, display the message with drupal_set_message().
421 */
422 function _resource_conflict_disable($type, $display = FALSE) {
423 // If the requirements are no longer met, disable resource checking and
424 // alert the site administrator.
425 if (variable_get('rc_type_' . $type, FALSE)) {
426 variable_del('rc_type_'. $type);
427 $msg = t('Resource Conflict has been disabled for the %type content type as the requirements for it are no longer met.', array('%type' => $type));
428
429 if ($display) {
430 drupal_set_message($msg, 'Resource Conflict');
431 }
432 watchdog('rsrc conflict', $msg, WATCHDOG_WARNING);
433 }
434 }
435
436 /**
437 * A function to display the database value for the date object
438 *
439 * @param $date - the date object
440 * @param $format - DATE_UNIX or DATE_ISO, the type of value to display
441 * @param $type - 'db' or 'local', the date value to display
442 */
443 if (!function_exists('date_show_value')) {
444 function date_show_value($date, $type = 'db', $format = DATE_ISO) {
445 if ($format == DATE_UNIX) {
446 return $date->$type->timestamp;
447 }
448 else {
449 return $date->$type->iso;
450 }
451 }
452 }

  ViewVC Help
Powered by ViewVC 1.1.2