| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: project.inc,v 1.147 2009/11/25 16:38:15 dww Exp $ 3 4 /** 5 * Implementation of hook_form(). 6 */ 7 function project_project_form($node, $form_state) { 8 global $user; 9 project_project_set_breadcrumb($node); 10 11 /* Project taxonomy */ 12 if (project_use_taxonomy()) { 13 // Since this form is used relatively infrequently, don't allow the js to be aggregated. 14 drupal_add_js(drupal_get_path('module', 'project') .'/project.js', 'module', 'header', FALSE, TRUE, FALSE); 15 $project_type_vid = _project_get_vid(); 16 $tree = taxonomy_get_tree($project_type_vid); 17 $top_level = array(); 18 $options = array(); 19 foreach ($tree as $i => $term) { 20 if ($term->parents[0] == 0) { 21 $last_top = $term->tid; 22 $top_level[$term->tid] = check_plain($term->name); 23 } 24 else { 25 $options[$last_top][$term->tid] = $term->name; 26 } 27 } 28 // See if there are any project specific taxonomy terms already 29 // saved in this node (i.e. we're editing an existing project) and 30 // if so, extract the right default values for our custom form 31 // elements... 32 $current_top = NULL; 33 $current_options = array(); 34 35 if (!empty($node->taxonomy)) { 36 // Depending on whether we're previewing the node or not, 37 // $node->taxonomy will be provided in one of two ways. 38 if (isset($form_state['node_preview'])) { 39 // In node previews, $node->taxonomy is an array of vocabularies, 40 // each of which is an array of selected tids. 41 if (isset($node->taxonomy[$project_type_vid])) { 42 foreach ($node->taxonomy[$project_type_vid] as $key => $value) { 43 if (isset($top_level[$key])) { 44 $current_top = $key; 45 } 46 else { 47 $current_options[$key] = $key; 48 } 49 } 50 } 51 } 52 else { 53 // $node->taxonomy is an array of term objects 54 // when we're not previewing the node. 55 foreach ($node->taxonomy as $tid => $obj) { 56 if (isset($top_level[$tid])) { 57 $current_top = $tid; 58 } 59 else { 60 $current_options[$tid] = $tid; 61 } 62 } 63 } 64 } 65 66 $form['project_taxonomy'] = array( 67 '#type' => 'fieldset', 68 '#weight' => '-30', 69 '#title' => t('Project categories'), 70 '#collapsible' => TRUE, 71 '#theme' => 'project_project_node_form_taxonomy', 72 ); 73 74 $form['project_taxonomy']['project_type'] = array( 75 '#title' => t('Project type'), 76 '#type' => 'radios', 77 '#options' => $top_level, 78 '#default_value' => $current_top, 79 '#required' => TRUE, 80 ); 81 $select_size = max(5, 2*count($top_level)); 82 foreach ($options as $tid => $values) { 83 $form['project_taxonomy']["tid_$tid"] = array( 84 '#title' => t('!type categories', array('!type' => $top_level[$tid])), 85 '#type' => 'select', 86 '#multiple' => TRUE, 87 '#options' => $values, 88 '#default_value' => $current_options, 89 '#attributes' => array('size' => min($select_size, count($values))), 90 ); 91 } 92 } 93 94 /* Project properties */ 95 // We can't put the title and body inside $node->project or core gets 96 // confused (e.g node_body_field() and friends). So, we put the core node 97 // fields in their own fieldset (for which is #tree is FALSE). 98 $form['project_node'] = array( 99 '#type' => 'fieldset', 100 '#title' => t('Project information'), 101 '#collapsible' => TRUE, 102 ); 103 $form['project_node']['title'] = array( 104 '#type' => 'textfield', 105 '#title' => t('Full project name'), 106 '#default_value' => isset($node->title) ? $node->title : NULL, 107 '#maxlength' => 128, 108 '#required' => TRUE, 109 ); 110 // This is sort of a hack: We want the 'uri' to be in the $node->project 111 // array during validation and submission of this form, to protect the $node 112 // namespace, even though from a usability standpoint, this field belongs 113 // right up next to the title. So, we add a 'project' subarray in here 114 // for which #tree is TRUE, and put the 'uri' field in there. That way, it 115 // still lives inside the "Project information" fieldset as far as the UI is 116 // concerned, but the value shows up in the $node->project array for 117 // validation and submission as far as FAPI is concerned. 118 $form['project_node']['project'] = array('#tree' => TRUE); 119 $form['project_node']['project']['uri'] = array( 120 '#type' => 'textfield', 121 '#title' => t('Short project name'), 122 '#default_value' => isset($node->project['uri']) ? $node->project['uri'] : NULL, 123 '#size' => 40, 124 '#maxlength' => 50, 125 '#description' => (variable_get('project_enable_alias', TRUE)) ? t('This will be used to generate a /project/<shortname>/ URL for your project.') : '', 126 '#required' => TRUE, 127 ); 128 $form['project_node']['body_field'] = node_body_field($node, t('Full description'), 1); 129 130 $form['project'] = array( 131 '#type' => 'fieldset', 132 '#title' => t('Project resources'), 133 '#collapsible' => TRUE, 134 '#collapsed' => TRUE, 135 '#tree' => TRUE, 136 ); 137 $form['project']['homepage'] = array( 138 '#type' => 'textfield', 139 '#title' => t('Homepage'), 140 '#default_value' => isset($node->project['homepage']) ? $node->project['homepage'] : NULL, 141 '#size' => 40, 142 '#maxlength' => 255, 143 '#description' => t('Link to project homepage.'), 144 ); 145 $form['project']['documentation'] = array( 146 '#type' => 'textfield', 147 '#title' => t('Documentation'), 148 '#default_value' => isset($node->project['documentation']) ? $node->project['documentation'] : NULL, 149 '#size' => 40, 150 '#maxlength' => 255, 151 '#description' => t('Link to project documentation.'), 152 ); 153 $form['project']['license'] = array( 154 '#type' => 'textfield', 155 '#title' => t('License'), 156 '#default_value' => isset($node->project['license']) ? $node->project['license'] : NULL, 157 '#size' => 40, 158 '#maxlength' => 255, 159 '#description' => t('Link to project license.'), 160 ); 161 $form['project']['screenshots'] = array( 162 '#type' => 'textfield', 163 '#title' => t('Screenshots'), 164 '#default_value' => isset($node->project['screenshots']) ? $node->project['screenshots'] : NULL, 165 '#size' => 40, 166 '#maxlength' => 255, 167 '#description' => t('Link to project screenshots.'), 168 ); 169 $form['project']['changelog'] = array( 170 '#type' => 'textfield', 171 '#title' => t('Changelog'), 172 '#default_value' => isset($node->project['changelog']) ? $node->project['changelog'] : NULL, 173 '#size' => 40, 174 '#maxlength' => 255, 175 '#description' => t('Link to changelog.'), 176 ); 177 $form['project']['cvs'] = array( 178 '#type' => 'textfield', 179 '#title' => t('CVS tree'), 180 '#default_value' => isset($node->project['cvs']) ? $node->project['cvs'] : NULL, 181 '#size' => 40, 182 '#maxlength' => 255, 183 '#description' => t('Link to webcvs/viewcvs.'), 184 ); 185 $form['project']['demo'] = array( 186 '#type' => 'textfield', 187 '#title' => t('Demo site'), 188 '#default_value' => isset($node->project['demo']) ? $node->project['demo'] : NULL, 189 '#size' => 40, 190 '#maxlength' => 255, 191 '#description' => t('Link to a live demo.'), 192 ); 193 194 return $form; 195 } 196 197 /** 198 * Implementation of hook_validate(). 199 * 200 * @param $node 201 * An object containing values from the project node form. Note that since 202 * this isn't a fully-loaded $node object, not all values will necessarily 203 * be in the same location as they would after a node_load(). 204 */ 205 function project_project_validate(&$node) { 206 // Bail if user hasn't done a preview yet. 207 if (!isset($node->title)) { 208 return $node; 209 } 210 211 // Make sure title isn't already in use 212 if (db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = '%s' AND status = %d AND title = '%s' AND nid <> %d", $node->type, 1, $node->title, $node->nid))) { 213 form_set_error('title', t('This project name is already in use.')); 214 } 215 216 // Validate uri. 217 if (empty($node->project['uri'])) { 218 form_set_error('project][uri', t('A short project name is required.')); 219 } 220 else { 221 // Make sure uri only includes valid characters 222 if (!preg_match('/^[a-zA-Z0-9_-]+$/', $node->project['uri'])) { 223 form_set_error('project][uri', t('Please only use alphanumerical characters for the project name.')); 224 } 225 226 // Make sure uri isn't already in use, or reserved. Includes all X from 227 // project/issues/X paths used in project_issues module 228 $reserved_names = array('user', 'issues', 'releases', 'rss', 'subscribe-mail', 'search', 'add', 'update_project', 'statistics', 'comments', 'autocomplete', 'cvs', 'developers', 'usage'); 229 if (project_use_taxonomy()) { 230 $terms = taxonomy_get_tree(_project_get_vid()); 231 foreach ($terms as $i => $term) { 232 if ($term->depth == 0) { 233 $reserved_names[] = strtolower($term->name); 234 } 235 } 236 } 237 if (in_array(strtolower($node->project['uri']), $reserved_names)) { 238 form_set_error('project][uri', t('This project name is reserved.')); 239 } 240 $existing_nid = project_get_nid_from_uri($node->project['uri']); 241 if (!empty($existing_nid) && $existing_nid != $node->nid) { 242 form_set_error('project][uri', t('This project name is already in use.')); 243 } 244 } 245 246 // Make sure all URL fields actually contain URLs. 247 $fields = array( 248 'homepage' => t('Homepage'), 249 'changelog' => t('Changelog'), 250 'cvs' => t('CVS tree'), 251 'demo' => t('Demo site'), 252 ); 253 foreach ($fields as $uri => $name) { 254 if ($node->project[$uri] && !preg_match('/^(http|https|ftp):\/\//i', $node->project[$uri])) { 255 form_set_error("project][$uri", t('The %field field is not a valid URL.', array('%field' => $name))); 256 } 257 } 258 259 // Validate the project-specific sub-categories, if any... 260 if (project_use_taxonomy() && isset($node->project_type)) { 261 $tree = taxonomy_get_tree(_project_get_vid()); 262 $top_level = array(); 263 foreach ($tree as $i => $term) { 264 if ($term->parents[0] == 0) { 265 $top_level[$term->tid] = $term->name; 266 } 267 } 268 foreach ($top_level as $tid => $name) { 269 if ($node->project_type != $tid) { 270 $tid_field = 'tid_' . $tid; 271 if (!empty($node->$tid_field)) { 272 form_set_error($tid, t('Project type %project_type was selected, you can not use values from %invalid_type categories', array('%project_type' => $top_level[$node->project_type], '%invalid_type' => $top_level[$tid]))); 273 } 274 } 275 } 276 } 277 } 278 279 function project_project_set_breadcrumb($node = NULL, $extra = NULL) { 280 $breadcrumb = array(); 281 $breadcrumb[] = l(t('Home'), NULL); 282 283 /* 284 @TODO: This is not an optimal way to do this, because it makes the 285 assumption that there is only one menu item that links to /project (or 286 whatever it happens to be called). Also, it makes the assumption that the 287 URL alias is intact for the project node (in other words, it's path is 288 aliased to 'project/<project short name>' However, since in D6 we no 289 longer have $_menu I'm not sure of a better way to do this. 290 */ 291 if (!empty($node->path)) { 292 // Get the path of the project node and remove the name of the project. 293 $path = array(); 294 $path = explode('/', $node->path); 295 $path = array_slice($path, 0, count($path) - 1); 296 $path = implode('/', $path); 297 $menu_link = db_fetch_object(db_query("SELECT * FROM {menu_links} ml INNER JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.hidden = %d AND ml.link_path = '%s' ORDER BY ml.weight", 0, $path)); 298 if (!empty($menu_link)) { 299 $breadcrumb[] = l($menu_link->link_title, 'project', array('title' => t('Browse projects'))); 300 } 301 } 302 303 if (!empty($node->nid) && project_use_taxonomy()) { 304 $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid INNER JOIN {term_node} r ON t.tid = r.tid WHERE h.parent = %d AND t.vid = %d AND r.vid = %d', 't', 'tid'), 0, _project_get_vid(), $node->vid); 305 if ($term = db_fetch_object($result)) { 306 $breadcrumb[] = l($term->name, 'project/'. $term->name); 307 } 308 } 309 310 if (is_array($extra)) { 311 $breadcrumb = array_merge($breadcrumb, $extra); 312 } 313 elseif ($extra && !empty($node)) { 314 $breadcrumb[] = l($node->title, 'node/'. $node->nid); 315 } 316 317 drupal_set_breadcrumb($breadcrumb); 318 } 319 320 function project_project_view($node, $teaser = false, $page = false) { 321 $node = node_prepare($node, $teaser); 322 323 if ($page) { 324 // Breadcrumb navigation 325 project_project_set_breadcrumb($node); 326 327 // If theme_project_release_project_download_table is implemented, format 328 // the download table. If this function is not implemented (eg. if the 329 // project_release module is not enabled), there will not be an error 330 // but of course there will be no release table. 331 $project_table_output = theme('project_release_project_download_table', $node); 332 if (!empty($project_table_output)) { 333 $node->content['download_table'] = array( 334 '#value' => $project_table_output, 335 '#weight' => 1, 336 ); 337 } 338 339 // Retrieve nested array of sections of links to display on node page. 340 $all_links = project_get_project_link_info($node); 341 342 // Format links in $all_links for display in the project_project node. 343 // Keep track of the section with the heaviest weight (which will be last) 344 // so we can add a final clear after it to make sure the floating link 345 // sections do not interfere with other formatting in the node's content. 346 $max_weight = -10000; 347 $last_section = ''; 348 foreach($all_links as $section => $values) { 349 // Only add the section if there are links, and section type is "inline". 350 if (!empty($values['links']) && (empty($values['type']) || $values['type'] == 'inline')) { 351 $weight = !empty($values['weight']) ? $values['weight'] : 0; 352 $node->content[$section] = array( 353 '#value' => theme('item_list', $values['links'], isset($values['name']) ? $values['name'] : NULL), 354 '#weight' => !empty($values['weight']) ? $values['weight'] : 0, 355 '#prefix' => '<div class="project-links-section" id="project-links-section-'. $section .'">', 356 '#suffix' => '</div>', 357 ); 358 if (!empty($values['clear'])) { 359 $node->content[$section]['#suffix'] .= '<br style="clear:both;" />'; 360 } 361 if ($weight >= $max_weight) { 362 $last_section = $section; 363 $max_weight = $weight; 364 } 365 } 366 } 367 // We only want to add a clearing <br> after the final section if that 368 // section didn't already add a clear for itself (e.g. the heaviest 369 // section might already clear from hook_project_page_link_alter()). 370 if (empty($all_links[$last_section]['clear']) && !empty($last_section)) { 371 $node->content[$last_section]['#suffix'] .= '<br style="clear:both;" />'; 372 } 373 } 374 return $node; 375 } 376 377 /** 378 * hook_nodeapi() implementation specific for project nodes. 379 * @see project_nodeapi(). 380 */ 381 function project_project_nodeapi(&$node, $op, $arg) { 382 $language = isset($node->language) ? $node->language : ''; 383 switch ($op) { 384 case 'insert': 385 _project_save_taxonomy($node); 386 if (module_exists('path') && variable_get('project_enable_alias', TRUE)) { 387 path_set_alias("node/$node->nid", 'project/'. $node->project['uri'], NULL, $language); 388 } 389 break; 390 391 case 'update': 392 _project_save_taxonomy($node); 393 if (module_exists('path') && variable_get('project_enable_alias', TRUE)) { 394 path_set_alias("node/$node->nid"); // Clear existing alias. 395 path_set_alias("node/$node->nid", 'project/'. $node->project['uri'], NULL, $language); 396 } 397 break; 398 } 399 } 400 401 function project_project_insert($node) { 402 db_query("INSERT INTO {project_projects} (nid, uri, homepage, changelog, cvs, demo, screenshots, documentation, license) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $node->nid, $node->project['uri'], $node->project['homepage'], $node->project['changelog'], $node->project['cvs'], $node->project['demo'], $node->project['screenshots'], $node->project['documentation'], $node->project['license']); 403 // project_release_scan_directory($node->project['uri']); 404 } 405 406 function project_project_update($node) { 407 db_query("UPDATE {project_projects} SET uri = '%s', homepage = '%s', changelog = '%s', cvs = '%s', demo = '%s', screenshots = '%s', documentation = '%s', license = '%s' WHERE nid = %d", $node->project['uri'], $node->project['homepage'], $node->project['changelog'], $node->project['cvs'], $node->project['demo'], $node->project['screenshots'], $node->project['documentation'], $node->project['license'], $node->nid); 408 // project_release_scan_directory($node->project['uri']); 409 } 410 411 function project_project_delete($node) { 412 db_query('DELETE FROM {project_projects} WHERE nid = %d', $node->nid); 413 } 414 415 function project_project_retrieve($key = 0) { 416 if (!is_numeric($key)) { 417 $nid = project_get_nid_from_uri($key); 418 } 419 $node = node_load($nid); 420 return ($node->type == 'project_project') ? $node : NULL; 421 } 422 423 function project_cvs($nid = 0) { 424 if ($project = node_load($nid)) { 425 if (node_access('view', $project)) { 426 $_REQUEST['nid'] = $nid; 427 $output = module_invoke('cvs', 'show_messages'); 428 drupal_set_title(t('CVS messages for %name', array('%name' => $project->title))); 429 project_project_set_breadcrumb($project, TRUE); 430 return $output; 431 } 432 else { 433 drupal_access_denied(); 434 } 435 } 436 else { 437 drupal_not_found(); 438 } 439 } 440 441 function _project_save_taxonomy(&$node) { 442 if (project_use_taxonomy() && $node->project_type) { 443 // First, clear out all terms from the project-specific taxonomy 444 // in this node. We'll re-add the right ones based on what's saved. 445 // This way, we're sure to clear out things that have been changed. 446 $vid = _project_get_vid(); 447 $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid); 448 $args = array($node->nid, $node->vid); 449 $terms = array(); 450 while ($item = db_fetch_object($result)) { 451 $terms[] = $item->tid; 452 } 453 if (count($terms) > 1) { 454 $sql = 'DELETE FROM {term_node} WHERE nid = %d AND vid = %d AND tid IN ('. db_placeholders($terms) .')'; 455 $args = array_merge($args, $terms); 456 db_query($sql, $args); 457 } 458 $tid = $node->project_type; 459 _project_db_save_taxonomy($node->nid, $tid, $node->vid); 460 $tid_field = 'tid_' . $tid; 461 if (isset($node->$tid_field)) { 462 foreach ($node->$tid_field as $tid) { 463 _project_db_save_taxonomy($node->nid, $tid, $node->vid); 464 } 465 } 466 } 467 } 468 469 function _project_db_save_taxonomy($nid, $tid, $vid) { 470 db_query('INSERT INTO {term_node} (nid, tid, vid) VALUES (%d, %d, %d)', $nid, $tid, $vid); 471 } 472 473 /** 474 * Adds the 'project-taxonomy-element' div to the project_type 475 * and term select box on the project_project node form. 476 */ 477 function theme_project_project_node_form_taxonomy($form) { 478 $output = ''; 479 foreach (element_children($form) as $child) { 480 $output .= '<div class="project-taxonomy-element">'; 481 $output .= drupal_render($form[$child]); 482 $output .= '</div>'; 483 } 484 return $output; 485 } 486 487 /** 488 * Build a nested array of sections of links to display on project_project node pages. 489 */ 490 function project_get_project_link_info($node = NULL) { 491 static $all_links; 492 493 // We only need to build the links array once per page. 494 if (is_array($all_links)) { 495 return $all_links; 496 } 497 498 // Resources section 499 $all_links['resources'] = array( 500 'name' => t('Resources'), 501 'weight' => 4, 502 'type' => 'inline', 503 ); 504 foreach (array('homepage' => t('Home page'), 'documentation' => t('Read documentation'), 'license' => t('Read license'), 'changelog' => t('Read complete log of changes'), 'demo' => t('Try out a demonstration'), 'screenshots' => t('Look at screenshots')) as $uri => $name) { 505 if (!empty($node->project[$uri])) { 506 $all_links['resources']['links'][$uri] = l($name, $node->project[$uri]); 507 } 508 } 509 510 // Developer section 511 $all_links['development'] = array( 512 'name' => t('Development'), 513 'weight' => 8, 514 'type' => 'inline', 515 ); 516 $links = array(); 517 if (!empty($node->project['cvs'])) { 518 $links['browse_repository'] = l(t('Browse the CVS repository'), $node->project['cvs']); 519 } 520 521 if (project_use_cvs($node)) { 522 $links['view_cvs_messages'] = l(t('View CVS messages'), 'project/cvs/'. $node->nid); 523 } 524 $all_links['development']['links'] = $links; 525 526 // Allow other modules to add sections of links and/or links to the sections defined above. 527 drupal_alter('project_page_link', $all_links, $node); 528 529 return $all_links; 530 } 531
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |