| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
// by Collective Colors - http://collectivecolors.com
|
| 4 |
|
| 5 |
/*******************************************************************************
|
| 6 |
* Template API
|
| 7 |
*
|
| 8 |
* The template api module provides a framework that allows for the management,
|
| 9 |
* evaluation, and rendering of templates.
|
| 10 |
*/
|
| 11 |
|
| 12 |
//------------------------------------------------------------------------------
|
| 13 |
// Template API constants (just in case we change the names later)
|
| 14 |
|
| 15 |
/**
|
| 16 |
* Prefix these constants with ([T]emplate [A]pplication [P]rograming
|
| 17 |
* [I]nterface) so that constants have a much smaller chance of conflicting
|
| 18 |
* with constants defined in the Drupal core and other Drupal modules.
|
| 19 |
*
|
| 20 |
* It's situations like this that truly makes me appreciate object oriented
|
| 21 |
* programming and encapsulation of class variables and constants.
|
| 22 |
*/
|
| 23 |
define("TAPI_XID_DEFAULT", 0);
|
| 24 |
|
| 25 |
define("TAPI_TYPE_DEFAULT", 'default');
|
| 26 |
define("TAPI_TYPE_TEMPLATE", 'tpid');
|
| 27 |
|
| 28 |
define('TAPI_FORMAT_ARRAY', 0);
|
| 29 |
define('TAPI_FORMAT_ASSOC', 1);
|
| 30 |
define('TAPI_FORMAT_TREE', 2);
|
| 31 |
|
| 32 |
define("TAPI_OP_CREATE", 0);
|
| 33 |
define("TAPI_OP_EDIT", 1);
|
| 34 |
define("TAPI_OP_ACTIVATE", 2);
|
| 35 |
define("TAPI_OP_DEACTIVATE", 3);
|
| 36 |
define("TAPI_OP_DELETE", 4);
|
| 37 |
|
| 38 |
//------------------------------------------------------------------------------
|
| 39 |
// Template API globals (equivalent to class variables for template functions)
|
| 40 |
|
| 41 |
$tapi_templates = array();
|
| 42 |
|
| 43 |
//------------------------------------------------------------------------------
|
| 44 |
// Drupal hooks
|
| 45 |
//------------------------------------------------------------------------------
|
| 46 |
|
| 47 |
/*******************************************************************************
|
| 48 |
* Implementation of hook_help
|
| 49 |
*/
|
| 50 |
function template_api_help($section) {
|
| 51 |
if ($section == 'admin/help#template_api') {
|
| 52 |
$output = "<p>The template api module provides a framework that allows for "
|
| 53 |
. "the management, evaluation, and rendering of templates.</p>";
|
| 54 |
}
|
| 55 |
return $output;
|
| 56 |
}
|
| 57 |
|
| 58 |
//------------------------------------------------------------------------------
|
| 59 |
// Template API
|
| 60 |
//
|
| 61 |
// This API does not handle user permissions. That responsibility is left to
|
| 62 |
// the modules that utilize this module.
|
| 63 |
//------------------------------------------------------------------------------
|
| 64 |
//------------------------------------------------------------------------------
|
| 65 |
// Template Management
|
| 66 |
|
| 67 |
/*******************************************************************************
|
| 68 |
* Retrieve templates
|
| 69 |
*
|
| 70 |
* This function caches templates that are fetched from the database which
|
| 71 |
* allows us to use this function to return formatted data objects with
|
| 72 |
* specified templates. If no ids are passed to this function the caching
|
| 73 |
* mechanism is bypassed and it acts like a refresh of the cache for the
|
| 74 |
* template type specified.
|
| 75 |
*
|
| 76 |
* @param mixed $ids - either an id number or an array of id numbers
|
| 77 |
* @param string $type - denotes the type of id number
|
| 78 |
* @param boolean $active - whether or not we want only active templates
|
| 79 |
* returned
|
| 80 |
* @param int $format - output format (FORMAT_ARRAY | FORMAT_ASSOC |
|
| 81 |
* FORMAT_TREE)
|
| 82 |
* @return array if format == FORMAT_TREE -> assoc[$type][$xid][] = $template
|
| 83 |
* if format == FORMAT_ASSOC -> assoc[$tpid] = $template
|
| 84 |
* if format == FORMAT_ARRAY -> array[] = $template
|
| 85 |
*/
|
| 86 |
function template_api_get_templates($ids = array(),
|
| 87 |
$type = TAPI_TYPE_TEMPLATE,
|
| 88 |
$active = TRUE,
|
| 89 |
$format = TAPI_FORMAT_ARRAY) {
|
| 90 |
global $tapi_templates;
|
| 91 |
|
| 92 |
// Allow for single id input.
|
| 93 |
if (is_numeric($ids)) {
|
| 94 |
$ids = array($ids);
|
| 95 |
}
|
| 96 |
|
| 97 |
// Find all templates that have not already been loaded into memory.
|
| 98 |
$new_ids = template_api_find_new_templates($ids, $type);
|
| 99 |
|
| 100 |
// We only want to query templates if no ids given or if there are uncached
|
| 101 |
// templates found.
|
| 102 |
if (!_valid_ids($ids) || count($new_ids)) {
|
| 103 |
$types_loaded = array();
|
| 104 |
$result = template_api_query_templates($new_ids, $type, $active);
|
| 105 |
|
| 106 |
while ($template = db_fetch_object($result)) {
|
| 107 |
|
| 108 |
// Load all external template data such as associated files and give
|
| 109 |
// external modules a chance to alter the template before it is added to
|
| 110 |
// the globally loaded templates.
|
| 111 |
template_api_load_template($template);
|
| 112 |
|
| 113 |
// Assign the same template to multiple tree branches so we can find it
|
| 114 |
// with different parameter sets and avoid extra database queries.
|
| 115 |
$tapi_templates[TAPI_TYPE_TEMPLATE][$template->tpid] = $template;
|
| 116 |
$tapi_templates[$template->type][$template->xid][] = $template;
|
| 117 |
$types_loaded[$template->type][$template->xid] = 1;
|
| 118 |
}
|
| 119 |
// Make sure templates from external types loaded are sorted by weight.
|
| 120 |
// Since different templates are loaded at different times we can not be
|
| 121 |
// sure that the templates are loaded in the proper order. By sorting
|
| 122 |
// directly after the query we can eliminate some extra sorting if we want
|
| 123 |
// to format an existing template multiple ways during execution.
|
| 124 |
foreach ($types_loaded as $type_loaded => $type_xids) {
|
| 125 |
foreach (array_keys($type_xids) as $type_xid) {
|
| 126 |
usort($tapi_templates[$type_loaded][$type_xid],
|
| 127 |
'template_api_compare_templates');
|
| 128 |
}
|
| 129 |
}
|
| 130 |
}
|
| 131 |
|
| 132 |
// We can format the output of the query in different ways which are useful
|
| 133 |
// for different purposes.
|
| 134 |
return template_api_format_templates($ids, $type, $active, $format);
|
| 135 |
}
|
| 136 |
|
| 137 |
/*******************************************************************************
|
| 138 |
* Retrieve a single template
|
| 139 |
*
|
| 140 |
* This function has the same basic features as the multi template version. It
|
| 141 |
* just returns the most negatively weighted template of the specified type if
|
| 142 |
* no id is given or if the id is not a template id (tpid). If just a template
|
| 143 |
* id is given, it returns the specified template.
|
| 144 |
*
|
| 145 |
* @param int $id - template id number (tpid) or external id number (xid)
|
| 146 |
* @param string $type - denotes the type of id number
|
| 147 |
* @param boolean $active - whether or not we want only active templates
|
| 148 |
* returned
|
| 149 |
* @return class - template object
|
| 150 |
*/
|
| 151 |
function template_api_get_template($id,
|
| 152 |
$type = TAPI_TYPE_TEMPLATE,
|
| 153 |
$active = TRUE) {
|
| 154 |
|
| 155 |
$templates = template_api_get_templates($id, $type, $active,
|
| 156 |
TAPI_FORMAT_ARRAY);
|
| 157 |
if (count($templates)) {
|
| 158 |
return $templates[0];
|
| 159 |
}
|
| 160 |
return NULL;
|
| 161 |
}
|
| 162 |
|
| 163 |
/*******************************************************************************
|
| 164 |
* Return a new default template
|
| 165 |
*
|
| 166 |
* @param int $xid - external id number
|
| 167 |
* @param string $type - denotes the type of id number
|
| 168 |
* @return class - default template object
|
| 169 |
*/
|
| 170 |
function template_api_get_default_template($xid, $type = TAPI_TYPE_DEFAULT) {
|
| 171 |
|
| 172 |
$template = new stdClass();
|
| 173 |
|
| 174 |
$template->tpid = NULL;
|
| 175 |
$template->type = $type;
|
| 176 |
$template->xid = $xid;
|
| 177 |
|
| 178 |
$template->name = '';
|
| 179 |
$template->description = '';
|
| 180 |
$template->active = 0;
|
| 181 |
$template->weight = 0;
|
| 182 |
|
| 183 |
$template->js = '';
|
| 184 |
$template->css = '';
|
| 185 |
$template->php = '';
|
| 186 |
|
| 187 |
// Give external modules a chance to initialize the default template before
|
| 188 |
// it is returned.
|
| 189 |
template_api_load_template($template, TRUE);
|
| 190 |
|
| 191 |
return $template;
|
| 192 |
}
|
| 193 |
|
| 194 |
/*******************************************************************************
|
| 195 |
* Make any last minute additions to the template before it is ready to be used
|
| 196 |
* to display nodes
|
| 197 |
*
|
| 198 |
* This function is meant for internal use only! If you need to load a template
|
| 199 |
* call template_api_get_templates(...), template_api_get_template(...), or
|
| 200 |
* template_api_get_default_template(...).
|
| 201 |
*
|
| 202 |
* @param class $template - base template object
|
| 203 |
* @param boolean $initialize - whether or not this template is newly created
|
| 204 |
* @return class - fully built template object
|
| 205 |
*/
|
| 206 |
function template_api_load_template(&$template, $default = FALSE) {
|
| 207 |
|
| 208 |
// Let external modules add to the template object as it is loaded. The
|
| 209 |
// template is passed by reference to allow other modules to edit or remove
|
| 210 |
// template fields and it provides a slight performance boost. Yay!
|
| 211 |
foreach (module_implements('load_template') as $module) {
|
| 212 |
if ($module != 'template_api') {
|
| 213 |
$function = $module . '_load_template';
|
| 214 |
$function($template, $default);
|
| 215 |
}
|
| 216 |
}
|
| 217 |
return $template;
|
| 218 |
}
|
| 219 |
|
| 220 |
/*******************************************************************************
|
| 221 |
* Find any id numbers of the specified type that are not yet loaded into memory
|
| 222 |
*
|
| 223 |
* @param array $ids - an array of id numbers
|
| 224 |
* @param string $type - denotes the type of id number
|
| 225 |
* @return array - array of new id numbers
|
| 226 |
*/
|
| 227 |
function template_api_find_new_templates($ids, $type = TAPI_TYPE_TEMPLATE) {
|
| 228 |
|
| 229 |
global $tapi_templates;
|
| 230 |
|
| 231 |
// Load all specified templates if no ids given or templates for type do not
|
| 232 |
// exist yet.
|
| 233 |
if (!_valid_ids($ids) || is_null($tapi_templates[$type])) {
|
| 234 |
return $ids;
|
| 235 |
}
|
| 236 |
// Check that all specified templates exist.
|
| 237 |
$new_ids = array();
|
| 238 |
|
| 239 |
foreach ($ids as $id) {
|
| 240 |
if (is_null($tapi_templates[$type][$id])) {
|
| 241 |
$new_ids[] = $id;
|
| 242 |
}
|
| 243 |
}
|
| 244 |
return $new_ids;
|
| 245 |
}
|
| 246 |
|
| 247 |
/*******************************************************************************
|
| 248 |
* Return specified templates in different data formats
|
| 249 |
*
|
| 250 |
* This function is meant for internal use only! If you want to return
|
| 251 |
* formatted output for templates, call template_api_get_templates(...) or
|
| 252 |
* template_api_get_template(...) because these functions will load a template
|
| 253 |
* if it is not yet loaded into memory. This function will NOT load new
|
| 254 |
* templates into memory so any template ids given must already be loaded.
|
| 255 |
*
|
| 256 |
* @param array $ids - an array of id numbers
|
| 257 |
* @param string $type - denotes the type of id number
|
| 258 |
* @param boolean $active - whether or not we want only active templates
|
| 259 |
* returned
|
| 260 |
* @param int $format - output format (FORMAT_ARRAY | FORMAT_ASSOC |
|
| 261 |
* FORMAT_TREE)
|
| 262 |
* @return array if format == FORMAT_TREE -> assoc[$type][$xid][] = $template
|
| 263 |
* if format == FORMAT_ASSOC -> assoc[$tpid] = $template
|
| 264 |
* if format == FORMAT_ARRAY -> array[] = $template
|
| 265 |
*/
|
| 266 |
function template_api_format_templates($ids,
|
| 267 |
$type = TAPI_TYPE_TEMPLATE,
|
| 268 |
$active = TRUE,
|
| 269 |
$format = TAPI_FORMAT_ARRAY) {
|
| 270 |
global $tapi_templates;
|
| 271 |
|
| 272 |
$output = array();
|
| 273 |
|
| 274 |
// If no ids are given then we load all the existing ids from the specified
|
| 275 |
// type
|
| 276 |
if (!_valid_ids($ids)) {
|
| 277 |
$ids = (is_array($tapi_templates[$type])
|
| 278 |
? array_keys($tapi_templates[$type])
|
| 279 |
: array());
|
| 280 |
}
|
| 281 |
|
| 282 |
foreach ($ids as $id) {
|
| 283 |
$id_templates = $tapi_templates[$type][$id];
|
| 284 |
|
| 285 |
// Continue to next id if template does not exist or convert template to an
|
| 286 |
// array if there is only one template. This is the case when the specified
|
| 287 |
// id is of type TYPE_TEMPLATE (tpid). If any other type is given then the
|
| 288 |
// id may contain multiple templates to traverse. We standardize the value
|
| 289 |
// so we can easily traverse over the id templates in both cases.
|
| 290 |
if (!$id_templates) {
|
| 291 |
continue;
|
| 292 |
}
|
| 293 |
elseif(is_object($id_templates)) {
|
| 294 |
$id_templates = array($id_templates);
|
| 295 |
}
|
| 296 |
|
| 297 |
foreach ($id_templates as $template) {
|
| 298 |
// Make sure that only the active templates are returned if the active
|
| 299 |
// flag is set to TRUE.
|
| 300 |
if ($active && !$template->active) {
|
| 301 |
continue;
|
| 302 |
}
|
| 303 |
// Template is good. Output it in the desired format.
|
| 304 |
switch ($format) {
|
| 305 |
case TAPI_FORMAT_TREE:
|
| 306 |
$output[$template->type][$template->xid][] = $template;
|
| 307 |
break;
|
| 308 |
|
| 309 |
case TAPI_FORMAT_ASSOC:
|
| 310 |
$output[$template->tpid] = $template;
|
| 311 |
break;
|
| 312 |
|
| 313 |
default:
|
| 314 |
$output[] = $template;
|
| 315 |
}
|
| 316 |
}
|
| 317 |
}
|
| 318 |
return $output;
|
| 319 |
}
|
| 320 |
|
| 321 |
/*******************************************************************************
|
| 322 |
* Return a database query resource for specified ids of type. If no ids are
|
| 323 |
* given then all templates are returned.
|
| 324 |
*
|
| 325 |
* This function is meant for internal use only! If you want to query templates
|
| 326 |
* it is best to use template_api_get_templates(...) or
|
| 327 |
* template_api_get_template(...). This function does not cache results and
|
| 328 |
* it does not add results to the global templates variable, which can cause
|
| 329 |
* redundant queries.
|
| 330 |
*
|
| 331 |
* @param array $ids - an array of id numbers
|
| 332 |
* @param string $type - denotes the type of id number
|
| 333 |
* @param boolean $active - whether or not we want only active templates
|
| 334 |
* returned
|
| 335 |
* @return class - template query resource
|
| 336 |
*/
|
| 337 |
function template_api_query_templates($ids = array(),
|
| 338 |
$type = TAPI_TYPE_TEMPLATE,
|
| 339 |
$active = TRUE) {
|
| 340 |
|
| 341 |
// Query all templates of type if no ids given.
|
| 342 |
if (!_valid_ids($ids)) {
|
| 343 |
return template_api_query_all_templates($type, $active);
|
| 344 |
}
|
| 345 |
|
| 346 |
// Format query for execution.
|
| 347 |
$field = ($type == TAPI_TYPE_TEMPLATE ? 't.tpid' : 't.xid');
|
| 348 |
$placeholders = implode(',', array_fill(0, count($ids), '%d'));
|
| 349 |
|
| 350 |
$conditions = ($active ? array('t.active = 1') : array());
|
| 351 |
$conditions[] = "($field IN ($placeholders))";
|
| 352 |
if ($type != TAPI_TYPE_TEMPLATE) {
|
| 353 |
$conditions[] = "t.type = '%s'";
|
| 354 |
}
|
| 355 |
|
| 356 |
$query = "SELECT * FROM {template} t "
|
| 357 |
. (count($conditions) ? 'WHERE ' . implode(' AND ', $conditions) : '')
|
| 358 |
. " ORDER BY t.tpid, t.weight ";
|
| 359 |
|
| 360 |
// Execute query and return database result resource.
|
| 361 |
return db_query($query, array_merge($ids, array ($type)));
|
| 362 |
}
|
| 363 |
|
| 364 |
/*******************************************************************************
|
| 365 |
* Return a database query resource for all ids of a specified type.
|
| 366 |
*
|
| 367 |
* This function is meant for internal use only! If you want to query templates
|
| 368 |
* it is best to use template_api_get_templates(...) or
|
| 369 |
* template_api_get_template(...). This function does not cache results and
|
| 370 |
* it does not add results to the global templates variable, which can cause
|
| 371 |
* redundant queries.
|
| 372 |
*
|
| 373 |
* @param string $type - template type
|
| 374 |
* @param boolean $active - whether or not we want only active templates
|
| 375 |
* returned
|
| 376 |
* @return class - template query resource
|
| 377 |
*/
|
| 378 |
function template_api_query_all_templates($type = TAPI_TYPE_TEMPLATE,
|
| 379 |
$active = TRUE) {
|
| 380 |
|
| 381 |
// Format query for execution.
|
| 382 |
$conditions = ($active ? array('t.active = 1') : array());
|
| 383 |
|
| 384 |
if ($type != TAPI_TYPE_TEMPLATE) {
|
| 385 |
$conditions[] = "t.type = '%s'";
|
| 386 |
}
|
| 387 |
|
| 388 |
$query = "SELECT * FROM {template} t "
|
| 389 |
. (count($conditions) ? 'WHERE ' . implode(' AND ', $conditions) : '')
|
| 390 |
. " ORDER BY t.tpid, t.weight";
|
| 391 |
|
| 392 |
// Execute query and return database result resource.
|
| 393 |
return db_query($query, $type);
|
| 394 |
}
|
| 395 |
|
| 396 |
/*******************************************************************************
|
| 397 |
* Insert a new template into the database
|
| 398 |
*
|
| 399 |
* If this function is given an existing template as its input then we assign
|
| 400 |
* the existing template a new template id before we save it to the database.
|
| 401 |
* This allows us to create a copy of an existing template without overwriting
|
| 402 |
* the original. If an existing template is passed in then the template object
|
| 403 |
* will be modified to reflect the new template object that was just created.
|
| 404 |
*
|
| 405 |
* @param class $template - template object
|
| 406 |
* @return boolean
|
| 407 |
*/
|
| 408 |
function template_api_create_template(&$template) {
|
| 409 |
|
| 410 |
$path = drupal_get_path('module', 'template_api');
|
| 411 |
require_once("$path/template_file.inc");
|
| 412 |
|
| 413 |
// We go ahead and assign the modified values back to the template itself
|
| 414 |
// so that we can continue using this template object in the calling code
|
| 415 |
// without worrying about divergent data.
|
| 416 |
$template->tpid = db_next_id("{template}_tpid");
|
| 417 |
|
| 418 |
$template->name = check_plain(trim($template->name));
|
| 419 |
$template->description = check_plain(trim($template->description));
|
| 420 |
|
| 421 |
// These don't need to have the markup checked because the css and js text
|
| 422 |
// is meant to be injected into the page and is not displayed on the screen.
|
| 423 |
// We don't check the php because it is meant to be executed anyway.
|
| 424 |
$template->css = trim($template->css);
|
| 425 |
$template->js = trim($template->js);
|
| 426 |
$template->php = trim($template->php);
|
| 427 |
|
| 428 |
// Insert the new template.
|
| 429 |
$result = db_query("INSERT INTO {template} "
|
| 430 |
. "(tpid, xid, type, "
|
| 431 |
. " name, description, "
|
| 432 |
. " css, js, php, "
|
| 433 |
. " active, weight) "
|
| 434 |
. " VALUES (%d, %d, '%s', "
|
| 435 |
. "'%s', '%s', '%s', '%s', '%s', %d, %d)",
|
| 436 |
|
| 437 |
$template->tpid,
|
| 438 |
$template->xid,
|
| 439 |
$template->type,
|
| 440 |
$template->name,
|
| 441 |
$template->description,
|
| 442 |
$template->css,
|
| 443 |
$template->js,
|
| 444 |
$template->php,
|
| 445 |
$template->active,
|
| 446 |
$template->weight);
|
| 447 |
if (!$result) {
|
| 448 |
return template_api_log_status('Template database insert failed.',
|
| 449 |
WATCHDOG_ERROR);
|
| 450 |
}
|
| 451 |
// Save template files to the file system.
|
| 452 |
if (!template_api_save_template_files($template->tpid,
|
| 453 |
$template->css,
|
| 454 |
$template->js)) {
|
| 455 |
return template_api_log_status('Template file creation failed.',
|
| 456 |
WATCHDOG_ERROR);
|
| 457 |
}
|
| 458 |
|
| 459 |
// Let external modules insert template object fields
|
| 460 |
foreach (module_implements('edit_template') as $module) {
|
| 461 |
if ($module != 'template_api') {
|
| 462 |
$function = $module . '_edit_template';
|
| 463 |
$function($template, TAPI_OP_CREATE);
|
| 464 |
}
|
| 465 |
}
|
| 466 |
return template_api_log_status('Template creation completed.');
|
| 467 |
}
|
| 468 |
|
| 469 |
/*******************************************************************************
|
| 470 |
* Update an existing template in the database
|
| 471 |
*
|
| 472 |
* @param class $template - template object
|
| 473 |
* @return boolean
|
| 474 |
*/
|
| 475 |
function template_api_save_template (&$template) {
|
| 476 |
|
| 477 |
$path = drupal_get_path('module', 'template_api');
|
| 478 |
require_once("$path/template_file.inc");
|
| 479 |
|
| 480 |
// We go ahead and assign the modified values back to the template itself
|
| 481 |
// so that we can continue using this template object in the calling code
|
| 482 |
// without worrying about divergent data.
|
| 483 |
$template->name = check_plain(trim($template->name));
|
| 484 |
$template->description = check_plain(trim($template->description));
|
| 485 |
|
| 486 |
// These don't need to have the markup checked because the css and js text
|
| 487 |
// is meant to be injected into the page and is not displayed on the screen.
|
| 488 |
// We don't check the php because it is meant to be executed anyway.
|
| 489 |
$template->css = trim($template->css);
|
| 490 |
$template->js = trim($template->js);
|
| 491 |
$template->php = trim($template->php);
|
| 492 |
|
| 493 |
// Update the existing template.
|
| 494 |
$result = db_query("UPDATE {template} SET"
|
| 495 |
. " xid = %d,"
|
| 496 |
. " type = '%s',"
|
| 497 |
. " name = '%s',"
|
| 498 |
. " description = '%s',"
|
| 499 |
. " css = '%s',"
|
| 500 |
. " js = '%s',"
|
| 501 |
. " php = '%s',"
|
| 502 |
. " active = %d,"
|
| 503 |
. " weight = %d"
|
| 504 |
. " WHERE tpid = %d",
|
| 505 |
|
| 506 |
$template->xid,
|
| 507 |
$template->type,
|
| 508 |
$template->name,
|
| 509 |
$template->description,
|
| 510 |
$template->css,
|
| 511 |
$template->js,
|
| 512 |
$template->php,
|
| 513 |
$template->active,
|
| 514 |
$template->weight,
|
| 515 |
$template->tpid);
|
| 516 |
if (!$result) {
|
| 517 |
return template_api_log_status('Template database update failed.',
|
| 518 |
WATCHDOG_ERROR);
|
| 519 |
}
|
| 520 |
// Save template files to the file system.
|
| 521 |
if (!template_api_save_template_files($template->tpid,
|
| 522 |
$template->css,
|
| 523 |
$template->js)) {
|
| 524 |
return template_api_log_status('Template file save failed.',
|
| 525 |
WATCHDOG_ERROR);
|
| 526 |
}
|
| 527 |
|
| 528 |
// Let external modules update template object fields
|
| 529 |
foreach (module_implements('edit_template') as $module) {
|
| 530 |
if ($module != 'template_api') {
|
| 531 |
$function = $module . '_edit_template';
|
| 532 |
$function($template, TAPI_OP_EDIT);
|
| 533 |
}
|
| 534 |
}
|
| 535 |
return template_api_log_status('Template save completed.');
|
| 536 |
}
|
| 537 |
|
| 538 |
/*******************************************************************************
|
| 539 |
* Activate a specified template
|
| 540 |
*
|
| 541 |
* @param class $template - template object
|
| 542 |
* @return boolean
|
| 543 |
*/
|
| 544 |
function template_api_activate_template(&$template) {
|
| 545 |
|
| 546 |
$result = db_query("UPDATE {template} t SET t.active = 1 WHERE t.tpid = %d",
|
| 547 |
$template->tpid);
|
| 548 |
if (!$result) {
|
| 549 |
return template_api_log_status("Template database activation failed.",
|
| 550 |
WATCHDOG_ERROR);
|
| 551 |
}
|
| 552 |
|
| 553 |
// Let external modules act on template activation.
|
| 554 |
foreach (module_implements('edit_template') as $module) {
|
| 555 |
if ($module != 'template_api') {
|
| 556 |
$function = $module . '_edit_template';
|
| 557 |
$function($template, TAPI_OP_ACTIVATE);
|
| 558 |
}
|
| 559 |
}
|
| 560 |
return template_api_log_status("Template activation completed.");
|
| 561 |
}
|
| 562 |
|
| 563 |
/*******************************************************************************
|
| 564 |
* Deactivate a specified template
|
| 565 |
*
|
| 566 |
* @param class $template - template object
|
| 567 |
* @return boolean
|
| 568 |
*/
|
| 569 |
function template_api_deactivate_template(&$template) {
|
| 570 |
|
| 571 |
$result = db_query("UPDATE {template} t SET t.active = 0 WHERE t.tpid = %d",
|
| 572 |
$template->tpid);
|
| 573 |
if (!$result) {
|
| 574 |
return template_api_log_status("Template database deactivation failed.",
|
| 575 |
WATCHDOG_ERROR);
|
| 576 |
}
|
| 577 |
|
| 578 |
// Let external modules act on template deactivation.
|
| 579 |
foreach (module_implements('edit_template') as $module) {
|
| 580 |
if ($module != 'template_api') {
|
| 581 |
$function = $module . '_edit_template';
|
| 582 |
$function($template, TAPI_OP_DEACTIVATE);
|
| 583 |
}
|
| 584 |
}
|
| 585 |
return template_api_log_status("Template deactivation completed.");
|
| 586 |
}
|
| 587 |
|
| 588 |
/*******************************************************************************
|
| 589 |
* Delete a specified template
|
| 590 |
*
|
| 591 |
* @param class $template - template object
|
| 592 |
* @return boolean
|
| 593 |
*/
|
| 594 |
function template_api_delete_template(&$template) {
|
| 595 |
|
| 596 |
$path = drupal_get_path('module', 'template_api');
|
| 597 |
require_once("$path/template_file.inc");
|
| 598 |
|
| 599 |
$result = db_query("DELETE FROM {template} WHERE tpid = %d",
|
| 600 |
$template->tpid);
|
| 601 |
if (!$result) {
|
| 602 |
return template_api_log_status('Template database delete failed.',
|
| 603 |
WATCHDOG_ERROR);
|
| 604 |
}
|
| 605 |
// Delete all template files if they exist.
|
| 606 |
if (!template_api_delete_template_files($template->tpid)) {
|
| 607 |
return template_api_log_status('Template file delete failed.',
|
| 608 |
WATCHDOG_ERROR);
|
| 609 |
}
|
| 610 |
|
| 611 |
// Let external modules delete template object fields.
|
| 612 |
foreach (module_implements('edit_template') as $module) {
|
| 613 |
if ($module != 'template_api') {
|
| 614 |
$function = $module . '_edit_template';
|
| 615 |
$function($template, TAPI_OP_DELETE);
|
| 616 |
}
|
| 617 |
}
|
| 618 |
return template_api_log_status("Template delete completed.");
|
| 619 |
}
|
| 620 |
|
| 621 |
//------------------------------------------------------------------------------
|
| 622 |
// Template Evaluation
|
| 623 |
|
| 624 |
/*******************************************************************************
|
| 625 |
* Render the template for output to the html page and inject necessary template
|
| 626 |
* files.
|
| 627 |
*
|
| 628 |
* If more parameters are passed into the function than just the node object
|
| 629 |
* then the parameters are available via the $params variable. The first param,
|
| 630 |
* $params[0] is set to the given parameter directly after the $nodes parameter.
|
| 631 |
*
|
| 632 |
* @param string $code - the template code
|
| 633 |
* @param array $nodes - an array of nodes to pass to the template code
|
| 634 |
* @return string - executed template code
|
| 635 |
*/
|
| 636 |
function template_api_render_template(&$template, $nodes) {
|
| 637 |
|
| 638 |
// Inject template css and javascipt files if they exist.
|
| 639 |
$path = drupal_get_path('module', 'template_api');
|
| 640 |
require_once("$path/template_file.inc");
|
| 641 |
|
| 642 |
template_api_inject_files($template->tpid);
|
| 643 |
|
| 644 |
// Evaluate the template code and render html output.
|
| 645 |
$output = '';
|
| 646 |
if (strlen(trim($template->php))) {
|
| 647 |
$params = array_slice(func_get_args(), 2);
|
| 648 |
|
| 649 |
ob_start();
|
| 650 |
print eval('?>'. $template->php);
|
| 651 |
$output = ob_get_contents();
|
| 652 |
ob_end_clean();
|
| 653 |
}
|
| 654 |
return $output;
|
| 655 |
}
|
| 656 |
|
| 657 |
/*******************************************************************************
|
| 658 |
* Return a fully rendered node ready to be manipulated in a template
|
| 659 |
*
|
| 660 |
* This function is basically ripped from the node module. I wish I could just
|
| 661 |
* call the node function itself, but the function 'node_view' returns a html
|
| 662 |
* rendering instead of the node object and we would not want to manipulate
|
| 663 |
* rendered html. Over abundant use of string replace is BAD, BAD, BAD!!!
|
| 664 |
* While I'm on my soap box here; Why in the hell are there two variables
|
| 665 |
* for displaying either a teaser or a page on the node functions. This in my
|
| 666 |
* opinion is bad design. You display one or the other, never both. So two
|
| 667 |
* variables is freakin redundant. But aside from these occasional mishaps,
|
| 668 |
* Drupal code is pretty clean. I just wish it was object oriented so you could
|
| 669 |
* better encapsulate variables and functions. Imagine Drupal code without
|
| 670 |
* function names that stretch for miles and miles and miles, etc... I would
|
| 671 |
* think that you could achieve the same kind of hook system by implementing
|
| 672 |
* interfaces that classes implement and using method relection to dynamically
|
| 673 |
* call interface methods. Oh well, we can dream can't we. Oh yeah,
|
| 674 |
* one other thing I wish, that Drupal was written in Java instead of PHP.
|
| 675 |
* I'll get off my soap box now.
|
| 676 |
*
|
| 677 |
* @param int $nid - node id number
|
| 678 |
* @param boolean $teaser - whether to render the node teaser or if not true
|
| 679 |
* this function will render the node body instead
|
| 680 |
* @param boolean $links - whether to render the links appended to the node by
|
| 681 |
* other modules
|
| 682 |
* @return class - node object
|
| 683 |
*/
|
| 684 |
function template_api_prepare_node($nid,
|
| 685 |
$teaser = TRUE,
|
| 686 |
$links = TRUE) {
|
| 687 |
|
| 688 |
$node = node_build_content(node_load($nid), $teaser, !$teaser);
|
| 689 |
|
| 690 |
if ($links) {
|
| 691 |
$node->links = module_invoke_all('link', 'node', $node, $teaser);
|
| 692 |
|
| 693 |
foreach (module_implements('link_alter') AS $module) {
|
| 694 |
$function = $module .'_link_alter';
|
| 695 |
$function($node, $node->links);
|
| 696 |
}
|
| 697 |
}
|
| 698 |
|
| 699 |
// Set the proper node part, then unset unused $node part so that a bad
|
| 700 |
// theme can not open a security hole.
|
| 701 |
$content = drupal_render($node->content);
|
| 702 |
if ($teaser) {
|
| 703 |
$node->teaser = $content;
|
| 704 |
unset($node->body);
|
| 705 |
}
|
| 706 |
else {
|
| 707 |
$node->body = $content;
|
| 708 |
unset($node->teaser);
|
| 709 |
}
|
| 710 |
|
| 711 |
// Allow modules to modify the fully-built node.
|
| 712 |
node_invoke_nodeapi($node, 'alter', $teaser, !$teaser);
|
| 713 |
|
| 714 |
return $node;
|
| 715 |
}
|
| 716 |
|
| 717 |
/*******************************************************************************
|
| 718 |
* Render a single node's fields from each node type in the given list of nodes
|
| 719 |
*
|
| 720 |
* @param array $nodes - array of node objects
|
| 721 |
* @param string $target - target HTML field for javascript insert
|
| 722 |
* @return string - HTML display of specified node fields with clickable
|
| 723 |
* interface
|
| 724 |
*/
|
| 725 |
function template_api_get_node_type_variables($nodes, $target) {
|
| 726 |
|
| 727 |
$output = '';
|
| 728 |
$types = array();
|
| 729 |
|
| 730 |
foreach ($nodes as $node) {
|
| 731 |
if (!array_key_exists($node->type, $types)) {
|
| 732 |
$output .= '<h2>' . t('Example of @type node type',
|
| 733 |
array('@type' => $node->type))
|
| 734 |
. '</h2>';
|
| 735 |
|
| 736 |
$output .= template_api_get_node_variables($node, $target);
|
| 737 |
|
| 738 |
$types[$node->type] = 1;
|
| 739 |
}
|
| 740 |
}
|
| 741 |
return $output;
|
| 742 |
}
|
| 743 |
|
| 744 |
/*******************************************************************************
|
| 745 |
* Render a single nodes fields and allows for clickable insertion of php code
|
| 746 |
* into target field
|
| 747 |
*
|
| 748 |
* This function is basically ripped from the contemplate.module
|
| 749 |
* Great function. Great module.
|
| 750 |
*
|
| 751 |
* @param assoc $assoc - associative array of data fields to recurse through
|
| 752 |
* @param string $target - target HTML field for javascript insert
|
| 753 |
* @param string $parents - used by recursion
|
| 754 |
* @param boolean $object - used by recursion
|
| 755 |
* @return string - HTML display of node fields with clickable interface
|
| 756 |
*/
|
| 757 |
function template_api_get_node_variables($assoc, $target,
|
| 758 |
$parents = FALSE,
|
| 759 |
$object = FALSE) {
|
| 760 |
if (is_object($assoc)) {
|
| 761 |
$assoc = (array)$assoc;
|
| 762 |
}
|
| 763 |
if (is_array($assoc)) {
|
| 764 |
$output .= "<dl>\n";
|
| 765 |
foreach($assoc as $field => $value) {
|
| 766 |
if ($parents) {
|
| 767 |
if ($object) {
|
| 768 |
$field = $parents . '->'. $field;
|
| 769 |
}
|
| 770 |
else {
|
| 771 |
if (is_int($field)) {
|
| 772 |
$field = $parents . '[' . $field . ']';
|
| 773 |
}
|
| 774 |
else {
|
| 775 |
$field = $parents . '[\'' . $field . '\']';
|
| 776 |
}
|
| 777 |
}
|
| 778 |
}
|
| 779 |
|
| 780 |
$type = "";
|
| 781 |
if (!is_string($value)) {
|
| 782 |
$type = " (" . gettype($value) . ")";
|
| 783 |
}
|
| 784 |
|
| 785 |
if (!is_array($value) && !is_object($value)) {
|
| 786 |
if ($field == 'title' || (substr($field, -9) == "['value']")) {
|
| 787 |
$security = t(" <span style='color:red;font-weight:bold'>**</span>");
|
| 788 |
$insert = "'<?php print check_plain(\$nodes[0]->"
|
| 789 |
. addslashes($field)
|
| 790 |
. ") ?>'";
|
| 791 |
}
|
| 792 |
else {
|
| 793 |
$security = '';
|
| 794 |
$insert = "'<?php print \$nodes[0]->". addslashes($field)
|
| 795 |
. " ?>'";
|
| 796 |
}
|
| 797 |
|
| 798 |
$output .= "<dt><a href=\"#\" "
|
| 799 |
. "onclick=\"insertAtCursor(document.getElementById"
|
| 800 |
. "('edit-$target'), $insert);return false;\" "
|
| 801 |
. "title=\"insert this variable into $target\">"
|
| 802 |
. "\$nodes[0]->$field</a>{$security}{$type}</dt>\n";
|
| 803 |
}
|
| 804 |
else {
|
| 805 |
$output .= "<dt>\$nodes[0]->$field$type</dt>\n";
|
| 806 |
}
|
| 807 |
|
| 808 |
$output .= "<dd>\n";
|
| 809 |
if (is_array($value)) {
|
| 810 |
$output .= template_api_get_node_variables($value,
|
| 811 |
$target, $field);
|
| 812 |
}
|
| 813 |
elseif (is_object($value)) {
|
| 814 |
$output .= template_api_get_node_variables((array)$value,
|
| 815 |
$target, $field, TRUE);
|
| 816 |
}
|
| 817 |
else {
|
| 818 |
$value = is_bool($value) ? ($value ? 'TRUE' : 'FALSE') : $value;
|
| 819 |
$output .= htmlspecialchars(print_r($value, TRUE)) . "\n";
|
| 820 |
}
|
| 821 |
$output .= "</dd>\n";
|
| 822 |
}
|
| 823 |
$output .= "</dl>\n";
|
| 824 |
}
|
| 825 |
return $output;
|
| 826 |
}
|
| 827 |
|
| 828 |
//------------------------------------------------------------------------------
|
| 829 |
// Auxillary Functions
|
| 830 |
|
| 831 |
/*******************************************************************************
|
| 832 |
* Log the status of an operation with the system and display a status message
|
| 833 |
*
|
| 834 |
* @param string $message - message to associate with event
|
| 835 |
* @param string $type - event type (WATCHDOG_NOTICE | WATCHDOG_WARNING |
|
| 836 |
* WATCHDOG_ERROR)
|
| 837 |
* @return boolean
|
| 838 |
*/
|
| 839 |
function template_api_log_status($message, $type = WATCHDOG_NOTICE) {
|
| 840 |
|
| 841 |
$ok = TRUE;
|
| 842 |
|
| 843 |
// Set session message to be displayed on web page
|
| 844 |
switch ($type) {
|
| 845 |
case WATCHDOG_NOTICE:
|
| 846 |
drupal_set_message(t($message), 'status');
|
| 847 |
break;
|
| 848 |
case WATCHDOG_WARNING:
|
| 849 |
case WATCHDOG_ERROR:
|
| 850 |
drupal_set_message(t($message), 'error');
|
| 851 |
$ok = FALSE;
|
| 852 |
break;
|
| 853 |
default:
|
| 854 |
return FALSE;
|
| 855 |
}
|
| 856 |
// Set log message that is stored and can be viewed later
|
| 857 |
watchdog("template api", t($message), $type, $_GET['q']);
|
| 858 |
|
| 859 |
return $ok;
|
| 860 |
}
|
| 861 |
|
| 862 |
/*******************************************************************************
|
| 863 |
* Compare two templates by weight for sort ordering of id templates
|
| 864 |
*
|
| 865 |
* @param class $t1 - template object
|
| 866 |
* @param class $t2 - template object
|
| 867 |
* @return int - [ 0 ] if templates are same weight
|
| 868 |
* [ 1 ] if second template has heavier weight
|
| 869 |
* [ -1 ] if first template has heavier weight
|
| 870 |
*/
|
| 871 |
function template_api_compare_templates($t1, $t2) {
|
| 872 |
if ($t1->weight == $t2->weight) {
|
| 873 |
return 0;
|
| 874 |
}
|
| 875 |
return ($t1->weight < $t2->weight ? -1 : 1);
|
| 876 |
}
|
| 877 |
|
| 878 |
/*******************************************************************************
|
| 879 |
* Validate id number input
|
| 880 |
*
|
| 881 |
* @param array $ids - an array of id numbers
|
| 882 |
* @return boolean
|
| 883 |
*/
|
| 884 |
function _valid_ids($ids) {
|
| 885 |
return (is_array($ids) && count($ids));
|
| 886 |
}
|