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

Contents of /contributions/modules/pds/pds.module

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


Revision 1.7 - (show annotations) (download) (as text)
Thu May 28 21:11:58 2009 UTC (6 months ago) by coltrane
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.6: +5 -4 lines
File MIME type: text/x-php
Removing paths as links to avoid confusion and simplify code. Unit wildcard now works. Handling specific path units much better by imploding arg().
1 <?php
2 // $Id: pds.module,v 1.6 2009/05/28 20:24:39 coltrane Exp $
3
4 /**
5 * Generic tool for storing and retrieving key-value data pairs for a Drupal path.
6 */
7
8 // Properties of PDS items.
9 define('PDS_INHERIT', 'inherit');
10 define('PDS_CHILD', 'child');
11
12 /**
13 * Implementation of hook_perm().
14 */
15 function pds_perm() {
16 return array('administer pds');
17 }
18
19 /**
20 * Implementation of hook_theme().
21 */
22 function pds_theme($existing, $type, $theme, $path) {
23 return array(
24 'pds_item_order_form' => array(
25 'arguments' => array('form' => NULL),
26 ),
27 );
28 }
29
30 /**
31 * Implementation of hook_menu().
32 */
33 function pds_menu() {
34 $items = array();
35
36 $items['admin/build/pds'] = array(
37 'title' => 'PDS',
38 'description' => 'Manage key-value data for Drupal paths.',
39 'page callback' => 'pds_overview',
40 'access arguments' => array('administer pds'),
41 'type' => MENU_NORMAL_ITEM,
42 'file' => 'pds_admin.inc',
43 );
44 $items['admin/build/pds/list'] = array(
45 'title' => 'List',
46 'type' => MENU_DEFAULT_LOCAL_TASK,
47 'weight' => -10,
48 );
49 $items['admin/build/pds/add'] = array(
50 'title' => 'Add',
51 'page callback' => 'drupal_get_form',
52 'page arguments' => array('pds_item_form'),
53 'access arguments' => array('administer pds'),
54 'type' => MENU_LOCAL_TASK,
55 'file' => 'pds_admin.inc',
56 );
57 $items['admin/build/pds/add/%pds_name'] = array(
58 'title' => 'Add',
59 'page callback' => 'drupal_get_form',
60 'page arguments' => array('pds_item_form', 4),
61 'access arguments' => array('administer pds'),
62 'type' => MENU_CALLBACK,
63 'file' => 'pds_admin.inc',
64 );
65 $items['admin/build/pds/edit/%pds_id'] = array(
66 'title' => 'Edit',
67 'page callback' => 'drupal_get_form',
68 'page arguments' => array('pds_item_form', 4),
69 'access arguments' => array('administer pds'),
70 'type' => MENU_CALLBACK,
71 'file' => 'pds_admin.inc',
72 );
73 $items['admin/build/pds/delete/%pds_id'] = array(
74 'title' => 'Delete',
75 'page callback' => 'drupal_get_form',
76 'page arguments' => array('pds_item_delete_confirm', 4),
77 'access arguments' => array('administer pds'),
78 'type' => MENU_CALLBACK,
79 'file' => 'pds_admin.inc',
80 );
81
82 $items['admin/build/pds/%pds_name'] = array(
83 'title callback' => '_pds_name_title',
84 'title arguments' => array(3, 'List'),
85 'page callback' => 'pds_item_list',
86 'page arguments' => array(3),
87 'access arguments' => array('administer pds'),
88 'type' => MENU_CALLBACK,
89 'file' => 'pds_admin.inc',
90 );
91
92 $items['admin/build/pds/order/%pds_name'] = array(
93 'title callback' => '_pds_name_title',
94 'title arguments' => array(4, 'Order'),
95 'access arguments' => array('administer pds'),
96 'page callback' => 'drupal_get_form',
97 'page arguments' => array('pds_item_order_form', 4),
98 'type' => MENU_CALLBACK,
99 'file' => 'pds_admin.inc',
100 );
101
102 return $items;
103 }
104
105 /**
106 * Title callback.
107 */
108 function _pds_name_title($pds_items, $page) {
109 $name = '';
110 if (!empty($pds_items)) {
111 $name = $pds_items[0]['pds_name'];
112 }
113 return t('@name @page', array('@name' => $name, '@page' => $page));
114 }
115
116 /**
117 * Menu argument load.
118 */
119 function pds_id_load($pds_id) {
120 $data = db_fetch_array(db_query("SELECT * FROM {pds_items} WHERE pds_id = %d", $pds_id));
121 return $data;
122 }
123
124 /**
125 * Menu argument load.
126 */
127 function pds_name_load($pds_name) {
128 $items = array();
129 $result = db_query("SELECT * FROM {pds_items} WHERE pds_name = '%s'", $pds_name);
130 while ($data = db_fetch_array($result)) {
131 $items[] = $data;
132 }
133 return !empty($items) ? $items : FALSE;
134 }
135
136 /**
137 * Public function for saving a PDS data item.
138 * All inserts and updates to PDS items should go through here to reset static caches.
139 * @param array A PDS data item array.
140 */
141 function pds_save($item) {
142 // Remap to internal indexes in case we were called externally.
143 _pds_internal_index($item);
144 _pds_cache(NULL, array(), TRUE);
145 if (empty($item['pds_id'])) {
146 // New item.
147 drupal_write_record('pds_items', $item);
148 }
149 else {
150 // Update existing item.
151 drupal_write_record('pds_items', $item, 'pds_id');
152 }
153 }
154
155 /**
156 * Public function for deleting a PDS data item.
157 * @param array A PDS data item array.
158 */
159 function pds_delete($item) {
160 // Remap to internal indexes in case we were called externally.
161 _pds_internal_index($item);
162 _pds_cache(NULL, array(), TRUE);
163 db_query("DELETE FROM {pds_items} WHERE pds_id = %d", $item['pds_id']);
164 }
165
166 /**
167 * Public function retrieves PDS key-value data by name for current path.
168 *
169 * @param string $name The name collection.
170 * @return array An array of PDS key, value, weight data items.
171 */
172 function pds_load($name) {
173 // Use current path.
174 $arg_pairs = _pds_arg_map(arg());
175 $current_pair = array_shift($arg_pairs);
176 $items = _pds_load($name, $current_pair['type'], $current_pair['unit']);
177
178 return !empty($items) ? _pds_index_items($items) : array();
179 }
180
181 /**
182 * Public function retrieves PDS key-value data by name for current path. Does deep search for items with inherit property.
183 *
184 * @param string $name The name collection.
185 * @return array An array of PDS key, value, weight data items.
186 */
187 function pds_inherit_load($name) {
188 // Use current path.
189 $arg_pairs = _pds_arg_map(arg(), PDS_INHERIT);
190 $current_pair = array_shift($arg_pairs);
191
192 // Load the items.
193 $items = _pds_deep_load($name, $current_pair, $arg_pairs);
194 $keys = array();
195 foreach ($items as $item) {
196 // Items defined for the current path get preference.
197 if ($item['pds_type'] == $current_pair['type'] && $item['pds_unit'] == $current_pair['unit']) { // TODO also check if we already have this key?
198 $inherit_items[] = $item;
199 // Record the key we've stored.
200 $keys[] = $item['pds_key'];
201 }
202 // Items with inheritance and not already stored go next.
203 elseif ($item['pds_properties'] == PDS_INHERIT && !in_array($item['pds_key'], $keys)) {
204 $inherit_items[] = $item;
205 // Record the key we've stored.
206 $keys[] = $item['pds_key'];
207 }
208 }
209 // Reindex the items and return if we've loaded any.
210 return !empty($inherit_items) ? _pds_index_items($inherit_items) : array();
211 }
212
213 /**
214 * Private function to retrieve all PDS items for a key.
215 */
216 function _pds_items_key_load($name, $key) {
217 $pds_items = array();
218 $result = db_query("SELECT * FROM {pds_items} WHERE pds_name = '%s' AND pds_key = '%s'", $name, $key);
219 while ($data = db_fetch_array($result)) {
220 $pds_items[] = $data;
221 }
222 return $pds_items;
223 }
224
225 /**
226 * Private function to retrieve PDS data by name for current path.
227 */
228 function _pds_load($name, $type, $unit) {
229 $cache_key = 'load-' . implode('-', array($name, $type, $unit));
230 $cache_hit = _pds_cache($cache_key);
231 // If we're storing PDS data statically return it.
232 if ($cache_hit !== FALSE) {
233 return $cache_hit;
234 }
235 $items = array();
236 $result = db_query("SELECT * FROM {pds_items} WHERE pds_name = '%s' AND pds_type = '%s' AND (pds_unit = '%s' || pds_unit = '*')", $name, $type, $unit);
237 while ($data = db_fetch_array($result)) {
238 $items[] = $data;
239 }
240
241 return !empty($items) ? _pds_cache($cache_key, $items) : array();
242 }
243
244 /**
245 * Private function to retrieve PDS key-value pairs by name for current path. Does deep search.
246 *
247 * @param string $name The name collection.
248 * @return array An array of key, value PDS items.
249 */
250 function _pds_deep_load($name, $current_pair, $arg_pairs) {
251 // Cache key is based on the current path.
252 $cache_key = 'deep-' . implode('-', array($name, $current_pair['type'], $current_pair['unit']));
253 $cache_hit = _pds_cache($cache_key);
254 // If we're storing PDS data statically return it.
255 if ($cache_hit !== FALSE) {
256 return $cache_hit;
257 }
258 array_unshift($arg_pairs, $current_pair);
259 // Retrieve all PDS items.
260 $items = array();
261 foreach ($arg_pairs as $pair) {
262 $items = array_merge($items, _pds_load($name, $pair['type'], $pair['unit']));
263 }
264
265 return !empty($items) ? _pds_cache($cache_key, $items) : array();
266 }
267
268 /**
269 * Private helper function for mapping path arguments to PDS type and unit.
270 */
271 function _pds_arg_map($args, $deep = NULL) {
272 $cache_key = 'args-' . implode('-', $args);
273 $cache_key .= !empty($deep) ? '-deep' : '';
274 $cache_hit = _pds_cache($cache_key);
275 if ($cache_hit !== FALSE) {
276 return $cache_hit;
277 }
278
279 $arg_pairs = array();
280 switch ($args[0]) {
281 case 'node':
282 // On node*.
283 _pds_arg_map_node($args, $arg_pairs, $deep);
284 break;
285 case 'taxonomy':
286 // On taxonomy/term*.
287 _pds_arg_map_term($args, $arg_pairs, $deep);
288 break;
289 default:
290 if (drupal_is_front_page()) {
291 $arg_pairs['path-front'] = array('type' => 'path', 'unit' => '<front>');
292 }
293 else {
294 $unit = implode('/', $args);
295 $arg_pairs['path-' . $unit] = array('type' => 'path', 'unit' => $unit);
296 }
297 break;
298 }
299
300 return _pds_cache($cache_key, $arg_pairs);
301 }
302
303 /**
304 * Part of _pds_arg_map() build type-unit pairs for node pages.
305 */
306 function _pds_arg_map_node($args, &$arg_pairs, $deep = NULL) {
307 if (is_numeric($args[1])) {
308 $arg_pairs['node-' . $args[1]] = array('type' => 'node', 'unit' => $args[1]);
309 // Load node and get type-units for each of its terms and their parents and children.
310 if ($deep) {
311 $node = menu_get_object('node');
312 if (!empty($node->taxonomy)) {
313 foreach ($node->taxonomy as $tid => $term) {
314 $arg_pairs['term-' . $tid] = array('type' => 'term', 'unit' => $tid);
315 // Woh, go deep.
316 $parents = taxonomy_get_parents($tid);
317 foreach ($parents as $ptid => $pterm) {
318 $arg_pairs['term-' . $ptid] = array('type' => 'term', 'unit' => $ptid);
319 }
320 if ($deep != PDS_INHERIT) {
321 $children = taxonomy_get_children($tid);
322 foreach ($children as $ctid => $cterm) {
323 $arg_pairs['term-' . $ctid] = array('type' => 'term', 'unit' => $ctid);
324 }
325 }
326 }
327 }
328 }
329 }
330 else if (drupal_is_front_page()) {
331 $arg_pairs['path-front'] = array('type' => 'path', 'unit' => '<front>');
332 }
333 else {
334 $arg_pairs['node-*'] = array('type' => 'node', 'unit' => '*');
335 }
336 }
337
338 /**
339 * Part of _pds_arg_map() build type-unit pairs for Taxonomy term pages.
340 */
341 function _pds_arg_map_term($args, &$arg_pairs, $deep) {
342 if (is_numeric($args[2])) {
343 $arg_pairs['term-' . $args[2]] = array('type' => 'term', 'unit' => $args[2]);
344 // Get type-unit for terms parents and children.
345 if ($deep) {
346 $parents = taxonomy_get_parents($args[2]);
347 foreach ($parents as $ptid => $pterm) {
348 $arg_pairs['term-' . $ptid] = array('type' => 'term', 'unit' => $ptid);
349 }
350 if ($deep != PDS_INHERIT) {
351 $children = taxonomy_get_children($tid);
352 foreach ($children as $ctid => $cterm) {
353 $arg_pairs['term-' . $ctid] = array('type' => 'term', 'unit' => $ctid);
354 }
355 }
356 }
357 }
358 else {
359 $arg_pairs['term-*'] = array('type' => 'term', 'unit' => '*');
360 }
361 }
362
363 /**
364 * Private helper for organizing PDS items into friendly format.
365 */
366 function _pds_index_items($pds_items) {
367 $keyvalues = array();
368 foreach ($pds_items as $item) {
369 $keyvalues[] = array(
370 'id' => $item['pds_id'],
371 'key' => $item['pds_key'],
372 'value' => $item['pds_value'],
373 'weight' => $item['pds_weight'],
374 );
375 }
376 return $keyvalues;
377 }
378
379 /**
380 * Private helper for ensuring PDS item is indexed as used internally.
381 */
382 function _pds_internal_index(&$item) {
383 foreach ($item as $index => $value) {
384 if (substr($index, 0, 3) != 'pds') {
385 $item['pds_' . $index] = $value;
386 unset($item[$index]);
387 }
388 }
389 }
390
391 /**
392 * Cache controller.
393 * @return array or false
394 */
395 function _pds_cache($name = NULL, $data = array(), $clear = FALSE) {
396 static $pds_cache = array();
397
398 if ($clear) {
399 $pds_cache = array();
400 return FALSE;
401 }
402 if (isset($pds_cache[$name])) {
403 return $pds_cache[$name];
404 }
405 if (!empty($data)) {
406 $pds_cache[$name] = $data;
407 return $data;
408 }
409 return FALSE;
410 }

  ViewVC Help
Powered by ViewVC 1.1.2