| [ Index ] |
PHP Cross Reference of Joomla 2.5.4 DE |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @package Joomla.Administrator 4 * @subpackage com_menus 5 * 6 * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved. 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 // No direct access. 11 defined('_JEXEC') or die; 12 13 // Include dependencies. 14 jimport('joomla.application.component.modeladmin'); 15 jimport('joomla.filesystem.file'); 16 jimport('joomla.filesystem.folder'); 17 jimport('joomla.tablenested'); 18 require_once JPATH_COMPONENT.'/helpers/menus.php'; 19 20 /** 21 * Menu Item Model for Menus. 22 * 23 * @package Joomla.Administrator 24 * @subpackage com_menus 25 * @since 1.6 26 */ 27 class MenusModelItem extends JModelAdmin 28 { 29 /** 30 * @var string The prefix to use with controller messages. 31 * @since 1.6 32 */ 33 protected $text_prefix = 'COM_MENUS_ITEM'; 34 35 /** 36 * @var string The help screen key for the menu item. 37 * @since 1.6 38 */ 39 protected $helpKey = 'JHELP_MENUS_MENU_ITEM_MANAGER_EDIT'; 40 41 /** 42 * @var string The help screen base URL for the menu item. 43 * @since 1.6 44 */ 45 protected $helpURL; 46 47 /** 48 * @var boolean True to use local lookup for the help screen. 49 * @since 1.6 50 */ 51 protected $helpLocal = false; 52 53 /** 54 * Method to test whether a record can be deleted. 55 * 56 * @param object A record object. 57 * 58 * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. 59 * @since 1.6 60 */ 61 protected function canDelete($record) 62 { 63 if (!empty($record->id)) { 64 if ($record->published != -2) { 65 return ; 66 } 67 $user = JFactory::getUser(); 68 69 return $user->authorise('core.delete', 'com_menus.item.'.(int) $record->id); 70 } 71 } 72 73 /** 74 * Method to test whether a record can have its state edited. 75 * 76 * @param object A record object. 77 * 78 * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. 79 * @since 1.6 80 */ 81 protected function canEditState($record) 82 { 83 $user = JFactory::getUser(); 84 85 if (!empty($record->id)) { 86 return $user->authorise('core.edit.state', 'com_menus.item.'.(int) $record->id); 87 } 88 // Default to component settings if menu item not known. 89 else { 90 return parent::canEditState($record); 91 } 92 } 93 94 /** 95 * Method to perform batch operations on an item or a set of items. 96 * 97 * @param array $commands An array of commands to perform. 98 * @param array $pks An array of item ids. 99 * @param array $contexts An array of item contexts. 100 * 101 * @return boolean Returns true on success, false on failure. 102 * 103 * @since 1.6 104 */ 105 public function batch($commands, $pks, $contexts) 106 { 107 // Sanitize user ids. 108 $pks = array_unique($pks); 109 JArrayHelper::toInteger($pks); 110 111 // Remove any values of zero. 112 if (array_search(0, $pks, true)) 113 { 114 unset($pks[array_search(0, $pks, true)]); 115 } 116 117 if (empty($pks)) 118 { 119 $this->setError(JText::_('COM_MENUS_NO_ITEM_SELECTED')); 120 return false; 121 } 122 123 $done = false; 124 125 if (!empty($commands['menu_id'])) 126 { 127 $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); 128 129 if ($cmd == 'c') 130 { 131 $result = $this->batchCopy($commands['menu_id'], $pks, $contexts); 132 if (is_array($result)) 133 { 134 $pks = $result; 135 } 136 else 137 { 138 return false; 139 } 140 } 141 elseif ($cmd == 'm' && !$this->batchMove($commands['menu_id'], $pks, $contexts)) 142 { 143 return false; 144 } 145 $done = true; 146 } 147 148 if (!empty($commands['assetgroup_id'])) 149 { 150 if (!$this->batchAccess($commands['assetgroup_id'], $pks, $contexts)) 151 { 152 return false; 153 } 154 155 $done = true; 156 } 157 158 if (!empty($commands['language_id'])) 159 { 160 if (!$this->batchLanguage($commands['language_id'], $pks, $contexts)) 161 { 162 return false; 163 } 164 165 $done = true; 166 } 167 168 if (!$done) 169 { 170 $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); 171 return false; 172 } 173 174 return true; 175 } 176 177 /** 178 * Batch copy menu items to a new menu or parent. 179 * 180 * @param integer $value The new menu or sub-item. 181 * @param array $pks An array of row IDs. 182 * @param array $contexts An array of item contexts. 183 * 184 * @return mixed An array of new IDs on success, boolean false on failure. 185 * 186 * @since 1.6 187 */ 188 protected function batchCopy($value, $pks, $contexts) 189 { 190 // $value comes as {menutype}.{parent_id} 191 $parts = explode('.', $value); 192 $menuType = $parts[0]; 193 $parentId = (int) JArrayHelper::getValue($parts, 1, 0); 194 195 $table = $this->getTable(); 196 $db = $this->getDbo(); 197 $query = $db->getQuery(true); 198 $i = 0; 199 200 // Check that the parent exists 201 if ($parentId) 202 { 203 if (!$table->load($parentId)) 204 { 205 if ($error = $table->getError()) 206 { 207 // Fatal error 208 $this->setError($error); 209 return false; 210 } 211 else 212 { 213 // Non-fatal error 214 $this->setError(JText::_('JGLOBAL_BATCH_MOVE_PARENT_NOT_FOUND')); 215 $parentId = 0; 216 } 217 } 218 } 219 220 // If the parent is 0, set it to the ID of the root item in the tree 221 if (empty($parentId)) 222 { 223 if (!$parentId = $table->getRootId()) 224 { 225 $this->setError($db->getErrorMsg()); 226 return false; 227 } 228 } 229 230 // Check that user has create permission for menus 231 $user = JFactory::getUser(); 232 if (!$user->authorise('core.create', 'com_menus')) 233 { 234 $this->setError(JText::_('COM_MENUS_BATCH_MENU_ITEM_CANNOT_CREATE')); 235 return false; 236 } 237 238 // We need to log the parent ID 239 $parents = array(); 240 241 // Calculate the emergency stop count as a precaution against a runaway loop bug 242 $query->select('COUNT(id)'); 243 $query->from($db->quoteName('#__menu')); 244 $db->setQuery($query); 245 $count = $db->loadResult(); 246 247 if ($error = $db->getErrorMsg()) 248 { 249 $this->setError($error); 250 return false; 251 } 252 253 // Parent exists so we let's proceed 254 while (!empty($pks) && $count > 0) 255 { 256 // Pop the first id off the stack 257 $pk = array_shift($pks); 258 259 $table->reset(); 260 261 // Check that the row actually exists 262 if (!$table->load($pk)) 263 { 264 if ($error = $table->getError()) 265 { 266 // Fatal error 267 $this->setError($error); 268 return false; 269 } 270 else 271 { 272 // Not fatal error 273 $this->setError(JText::sprintf('JGLOBAL_BATCH_MOVE_ROW_NOT_FOUND', $pk)); 274 continue; 275 } 276 } 277 278 // Copy is a bit tricky, because we also need to copy the children 279 $query->clear(); 280 $query->select('id'); 281 $query->from($db->quoteName('#__menu')); 282 $query->where('lft > ' . (int) $table->lft); 283 $query->where('rgt < ' . (int) $table->rgt); 284 $db->setQuery($query); 285 $childIds = $db->loadColumn(); 286 287 // Add child ID's to the array only if they aren't already there. 288 foreach ($childIds as $childId) 289 { 290 if (!in_array($childId, $pks)) 291 { 292 array_push($pks, $childId); 293 } 294 } 295 296 // Make a copy of the old ID and Parent ID 297 $oldId = $table->id; 298 $oldParentId = $table->parent_id; 299 300 // Reset the id because we are making a copy. 301 $table->id = 0; 302 303 // If we a copying children, the Old ID will turn up in the parents list 304 // otherwise it's a new top level item 305 $table->parent_id = isset($parents[$oldParentId]) ? $parents[$oldParentId] : $parentId; 306 $table->menutype = $menuType; 307 308 // Set the new location in the tree for the node. 309 $table->setLocation($table->parent_id, 'last-child'); 310 311 // TODO: Deal with ordering? 312 //$table->ordering = 1; 313 $table->level = null; 314 $table->lft = null; 315 $table->rgt = null; 316 $table->home = 0; 317 318 // Alter the title & alias 319 list($title, $alias) = $this->generateNewTitle($table->parent_id, $table->alias, $table->title); 320 $table->title = $title; 321 $table->alias = $alias; 322 323 // Check the row. 324 if (!$table->check()) 325 { 326 $this->setError($table->getError()); 327 return false; 328 } 329 // Store the row. 330 if (!$table->store()) 331 { 332 $this->setError($table->getError()); 333 return false; 334 } 335 336 // Get the new item ID 337 $newId = $table->get('id'); 338 339 // Add the new ID to the array 340 $newIds[$i] = $newId; 341 $i++; 342 343 // Now we log the old 'parent' to the new 'parent' 344 $parents[$oldId] = $table->id; 345 $count--; 346 } 347 348 // Rebuild the hierarchy. 349 if (!$table->rebuild()) 350 { 351 $this->setError($table->getError()); 352 return false; 353 } 354 355 // Rebuild the tree path. 356 if (!$table->rebuildPath($table->id)) 357 { 358 $this->setError($table->getError()); 359 return false; 360 } 361 362 // Clean the cache 363 $this->cleanCache(); 364 365 return $newIds; 366 } 367 368 /** 369 * Batch move menu items to a new menu or parent. 370 * 371 * @param integer $value The new menu or sub-item. 372 * @param array $pks An array of row IDs. 373 * @param array $contexts An array of item contexts. 374 * 375 * @return boolean True on success. 376 * 377 * @since 1.6 378 */ 379 protected function batchMove($value, $pks, $contexts) 380 { 381 // $value comes as {menutype}.{parent_id} 382 $parts = explode('.', $value); 383 $menuType = $parts[0]; 384 $parentId = (int) JArrayHelper::getValue($parts, 1, 0); 385 386 $table = $this->getTable(); 387 $db = $this->getDbo(); 388 $query = $db->getQuery(true); 389 390 // Check that the parent exists. 391 if ($parentId) 392 { 393 if (!$table->load($parentId)) 394 { 395 if ($error = $table->getError()) 396 { 397 // Fatal error 398 $this->setError($error); 399 400 return false; 401 } 402 else 403 { 404 // Non-fatal error 405 $this->setError(JText::_('JGLOBAL_BATCH_MOVE_PARENT_NOT_FOUND')); 406 $parentId = 0; 407 } 408 } 409 } 410 411 // Check that user has create and edit permission for menus 412 $user = JFactory::getUser(); 413 if (!$user->authorise('core.create', 'com_menus')) 414 { 415 $this->setError(JText::_('COM_MENUS_BATCH_MENU_ITEM_CANNOT_CREATE')); 416 return false; 417 } 418 419 if (!$user->authorise('core.edit', 'com_menus')) 420 { 421 $this->setError(JText::_('COM_MENUS_BATCH_MENU_ITEM_CANNOT_EDIT')); 422 return false; 423 } 424 425 // We are going to store all the children and just moved the menutype 426 $children = array(); 427 428 // Parent exists so we let's proceed 429 foreach ($pks as $pk) 430 { 431 // Check that the row actually exists 432 if (!$table->load($pk)) 433 { 434 if ($error = $table->getError()) 435 { 436 // Fatal error 437 $this->setError($error); 438 return false; 439 } 440 else 441 { 442 // Not fatal error 443 $this->setError(JText::sprintf('JGLOBAL_BATCH_MOVE_ROW_NOT_FOUND', $pk)); 444 continue; 445 } 446 } 447 448 // Set the new location in the tree for the node. 449 $table->setLocation($parentId, 'last-child'); 450 451 // Set the new Parent Id 452 $table->parent_id = $parentId; 453 454 // Check if we are moving to a different menu 455 if ($menuType != $table->menutype) 456 { 457 // Add the child node ids to the children array. 458 $query->clear(); 459 $query->select($db->quoteName('id')); 460 $query->from($db->quoteName('#__menu')); 461 $query->where($db->quoteName('lft') .' BETWEEN ' . (int) $table->lft . ' AND ' . (int) $table->rgt); 462 $db->setQuery($query); 463 $children = array_merge($children, (array) $db->loadColumn()); 464 } 465 466 // Check the row. 467 if (!$table->check()) 468 { 469 $this->setError($table->getError()); 470 return false; 471 } 472 473 // Store the row. 474 if (!$table->store()) 475 { 476 $this->setError($table->getError()); 477 return false; 478 } 479 480 // Rebuild the tree path. 481 if (!$table->rebuildPath()) 482 { 483 $this->setError($table->getError()); 484 return false; 485 } 486 } 487 488 // Process the child rows 489 if (!empty($children)) 490 { 491 // Remove any duplicates and sanitize ids. 492 $children = array_unique($children); 493 JArrayHelper::toInteger($children); 494 495 // Update the menutype field in all nodes where necessary. 496 $query->clear(); 497 $query->update($db->quoteName('#__menu')); 498 $query->set($db->quoteName('menutype') . ' = ' . $db->quote($menuType)); 499 $query->where($db->quoteName('id') . ' IN (' . implode(',', $children) . ')'); 500 $db->setQuery($query); 501 $db->query(); 502 503 // Check for a database error. 504 if ($db->getErrorNum()) 505 { 506 $this->setError($db->getErrorMsg()); 507 return false; 508 } 509 } 510 511 // Clean the cache 512 $this->cleanCache(); 513 514 return true; 515 } 516 517 /** 518 * Method to check if you can save a record. 519 * 520 * @param array $data An array of input data. 521 * @param string $key The name of the key for the primary key. 522 * 523 * @return boolean 524 * @since 1.6 525 */ 526 protected function canSave($data = array(), $key = 'id') 527 { 528 return JFactory::getUser()->authorise('core.edit', $this->option); 529 } 530 531 /** 532 * Method to get the row form. 533 * 534 * @param array $data Data for the form. 535 * @param boolean $loadData True if the form is to load its own data (default case), false if not. 536 * @return mixed A JForm object on success, false on failure 537 * @since 1.6 538 */ 539 public function getForm($data = array(), $loadData = true) 540 { 541 // The folder and element vars are passed when saving the form. 542 if (empty($data)) { 543 $item = $this->getItem(); 544 $this->setState('item.link', $item->link); 545 // The type should already be set. 546 } 547 else { 548 $this->setState('item.link', JArrayHelper::getValue($data, 'link')); 549 $this->setState('item.type', JArrayHelper::getValue($data, 'type')); 550 } 551 552 // Get the form. 553 $form = $this->loadForm('com_menus.item', 'item', array('control' => 'jform', 'load_data' => $loadData), true); 554 if (empty($form)) { 555 return false; 556 } 557 558 // Modify the form based on access controls. 559 if (!$this->canEditState((object) $data)) { 560 // Disable fields for display. 561 $form->setFieldAttribute('menuordering', 'disabled', 'true'); 562 $form->setFieldAttribute('published', 'disabled', 'true'); 563 564 // Disable fields while saving. 565 // The controller has already verified this is an article you can edit. 566 $form->setFieldAttribute('menuordering', 'filter', 'unset'); 567 $form->setFieldAttribute('published', 'filter', 'unset'); 568 } 569 570 return $form; 571 } 572 573 /** 574 * Method to get the data that should be injected in the form. 575 * 576 * @return mixed The data for the form. 577 * @since 1.6 578 */ 579 protected function loadFormData() 580 { 581 // Check the session for previously entered form data. 582 return array_merge((array)$this->getItem(), (array)JFactory::getApplication()->getUserState('com_menus.edit.item.data', array())); 583 } 584 585 /** 586 * Get the necessary data to load an item help screen. 587 * 588 * @return object An object with key, url, and local properties for loading the item help screen. 589 * @since 1.6 590 */ 591 public function getHelp() 592 { 593 return (object) array('key' => $this->helpKey, 'url' => $this->helpURL, 'local' => $this->helpLocal); 594 } 595 596 /** 597 * Method to get a menu item. 598 * 599 * @param integer $pk An optional id of the object to get, otherwise the id from the model state is used. 600 * 601 * @return mixed Menu item data object on success, false on failure. 602 * @since 1.6 603 */ 604 public function getItem($pk = null) 605 { 606 // Initialise variables. 607 $pk = (!empty($pk)) ? $pk : (int)$this->getState('item.id'); 608 609 // Get a level row instance. 610 $table = $this->getTable(); 611 612 // Attempt to load the row. 613 $table->load($pk); 614 615 // Check for a table object error. 616 if ($error = $table->getError()) { 617 $this->setError($error); 618 $false = false; 619 return $false; 620 } 621 622 // Prime required properties. 623 624 if ($type = $this->getState('item.type')) { 625 $table->type = $type; 626 } 627 628 if (empty($table->id)) { 629 $table->parent_id = $this->getState('item.parent_id'); 630 $table->menutype = $this->getState('item.menutype'); 631 $table->params = '{}'; 632 } 633 634 // If the link has been set in the state, possibly changing link type. 635 if ($link = $this->getState('item.link')) { 636 // Check if we are changing away from the actual link type. 637 if (MenusHelper::getLinkKey($table->link) != MenusHelper::getLinkKey($link)) { 638 $table->link = $link; 639 } 640 } 641 642 switch ($table->type) 643 { 644 case 'alias': 645 $table->component_id = 0; 646 $args = array(); 647 648 parse_str(parse_url($table->link, PHP_URL_QUERY), $args); 649 break; 650 651 case 'separator': 652 $table->link = ''; 653 $table->component_id = 0; 654 break; 655 656 case 'url': 657 $table->component_id = 0; 658 659 parse_str(parse_url($table->link, PHP_URL_QUERY)); 660 break; 661 662 case 'component': 663 default: 664 // Enforce a valid type. 665 $table->type = 'component'; 666 667 // Ensure the integrity of the component_id field is maintained, particularly when changing the menu item type. 668 $args = array(); 669 parse_str(parse_url($table->link, PHP_URL_QUERY), $args); 670 671 if (isset($args['option'])) { 672 // Load the language file for the component. 673 $lang = JFactory::getLanguage(); 674 $lang->load($args['option'], JPATH_ADMINISTRATOR, null, false, false) 675 || $lang->load($args['option'], JPATH_ADMINISTRATOR.'/components/'.$args['option'], null, false, false) 676 || $lang->load($args['option'], JPATH_ADMINISTRATOR, $lang->getDefault(), false, false) 677 || $lang->load($args['option'], JPATH_ADMINISTRATOR.'/components/'.$args['option'], $lang->getDefault(), false, false); 678 679 // Determine the component id. 680 $component = JComponentHelper::getComponent($args['option']); 681 if (isset($component->id)) { 682 $table->component_id = $component->id; 683 } 684 } 685 break; 686 } 687 688 // We have a valid type, inject it into the state for forms to use. 689 $this->setState('item.type', $table->type); 690 691 // Convert to the JObject before adding the params. 692 $properties = $table->getProperties(1); 693 $result = JArrayHelper::toObject($properties, 'JObject'); 694 695 // Convert the params field to an array. 696 $registry = new JRegistry; 697 $registry->loadString($table->params); 698 $result->params = $registry->toArray(); 699 700 // Merge the request arguments in to the params for a component. 701 if ($table->type == 'component') { 702 // Note that all request arguments become reserved parameter names. 703 $result->request = $args; 704 $result->params = array_merge($result->params, $args); 705 } 706 707 if ($table->type == 'alias') { 708 // Note that all request arguments become reserved parameter names. 709 $args = array(); 710 parse_str(parse_url($table->link, PHP_URL_QUERY), $args); 711 $result->params = array_merge($result->params, $args); 712 } 713 714 if ($table->type == 'url') { 715 // Note that all request arguments become reserved parameter names. 716 $args = array(); 717 parse_str(parse_url($table->link, PHP_URL_QUERY), $args); 718 $result->params = array_merge($result->params, $args); 719 } 720 721 // Load associated menu items 722 if (JFactory::getApplication()->get('menu_associations', 0)) { 723 if ($pk != null) { 724 $result->associations = MenusHelper::getAssociations($pk); 725 } 726 else { 727 $result->associations = array(); 728 } 729 } 730 $result->menuordering = $pk; 731 732 return $result; 733 } 734 735 /** 736 * Get the list of modules not in trash. 737 * 738 * @return mixed An array of module records (id, title, position), or false on error. 739 * @since 1.6 740 */ 741 public function getModules() 742 { 743 $db = $this->getDbo(); 744 $query = $db->getQuery(true); 745 746 // Join on the module-to-menu mapping table. 747 // We are only interested if the module is displayed on ALL or THIS menu item (or the inverse ID number). 748 //sqlsrv changes for modulelink to menu manager 749 $query->select('a.id, a.title, a.position, a.published, map.menuid'); 750 $case_when = ' (CASE WHEN '; 751 $case_when .= 'map2.menuid < 0 THEN map2.menuid ELSE NULL END) as ' . $db->qn('except'); 752 $case_when .=$query->select( $case_when); 753 $query->from('#__modules AS a'); 754 $query->join('LEFT', '#__modules_menu AS map ON map.moduleid = a.id AND (map.menuid = 0 OR ABS(map.menuid) = '.(int) $this->getState('item.id').')'); 755 $query->join('LEFT', '#__modules_menu AS map2 ON map2.moduleid = a.id AND map2.menuid < 0'); 756 757 // Join on the asset groups table. 758 $query->select('ag.title AS access_title'); 759 $query->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); 760 $query->where('a.published >= 0'); 761 $query->where('a.client_id = 0'); 762 $query->order('a.position, a.ordering'); 763 764 $db->setQuery($query); 765 $result = $db->loadObjectList(); 766 767 if ($db->getErrorNum()) { 768 $this->setError($db->getErrorMsg()); 769 return false; 770 } 771 772 return $result; 773 } 774 775 /** 776 * A protected method to get the where clause for the reorder 777 * This ensures that the row will be moved relative to a row with the same menutype 778 * 779 * @param JTableMenu $table instance 780 * 781 * @return array An array of conditions to add to add to ordering queries. 782 * @since 1.6 783 */ 784 protected function getReorderConditions($table) 785 { 786 return 'menutype = ' . $this->_db->Quote($table->menutype); 787 } 788 789 /** 790 * Returns a Table object, always creating it 791 * 792 * @param type $type The table type to instantiate 793 * @param string $prefix A prefix for the table class name. Optional. 794 * @param array $config Configuration array for model. Optional. 795 * 796 * @return JTable A database object 797 * @since 1.6 798 */ 799 public function getTable($type = 'Menu', $prefix = 'MenusTable', $config = array()) 800 { 801 return JTable::getInstance($type, $prefix, $config); 802 } 803 804 /** 805 * Auto-populate the model state. 806 * 807 * Note. Calling getState in this method will result in recursion. 808 * 809 * @return void 810 * @since 1.6 811 */ 812 protected function populateState() 813 { 814 $app = JFactory::getApplication('administrator'); 815 816 // Load the User state. 817 $pk = (int) JRequest::getInt('id'); 818 $this->setState('item.id', $pk); 819 820 if (!($parentId = $app->getUserState('com_menus.edit.item.parent_id'))) { 821 $parentId = JRequest::getInt('parent_id'); 822 } 823 $this->setState('item.parent_id', $parentId); 824 825 $menuType = $app->getUserState('com_menus.edit.item.menutype'); 826 if (JRequest::getCmd('menutype', false)) { 827 $menuType = JRequest::getCmd('menutype', 'mainmenu'); 828 } 829 $this->setState('item.menutype', $menuType); 830 831 if (!($type = $app->getUserState('com_menus.edit.item.type'))){ 832 $type = JRequest::getCmd('type'); 833 // Note a new menu item will have no field type. 834 // The field is required so the user has to change it. 835 } 836 $this->setState('item.type', $type); 837 838 if ($link = $app->getUserState('com_menus.edit.item.link')) { 839 $this->setState('item.link', $link); 840 } 841 842 // Load the parameters. 843 $params = JComponentHelper::getParams('com_menus'); 844 $this->setState('params', $params); 845 } 846 847 /** 848 * @param object $form A form object. 849 * @param mixed $data The data expected for the form. 850 * 851 * @return void 852 * @since 1.6 853 * @throws Exception if there is an error in the form event. 854 */ 855 protected function preprocessForm(JForm $form, $data, $group = 'content') 856 { 857 858 // Initialise variables. 859 $link = $this->getState('item.link'); 860 $type = $this->getState('item.type'); 861 $formFile = false; 862 863 // Initialise form with component view params if available. 864 if ($type == 'component') { 865 866 $link = htmlspecialchars_decode($link); 867 868 // Parse the link arguments. 869 $args = array(); 870 parse_str(parse_url(htmlspecialchars_decode($link), PHP_URL_QUERY), $args); 871 872 // Confirm that the option is defined. 873 $option = ''; 874 $base = ''; 875 if (isset($args['option'])) { 876 // The option determines the base path to work with. 877 $option = $args['option']; 878 $base = JPATH_SITE.'/components/'.$option; 879 } 880 881 // Confirm a view is defined. 882 $formFile = false; 883 if (isset($args['view'])) { 884 $view = $args['view']; 885 886 // Determine the layout to search for. 887 if (isset($args['layout'])) { 888 $layout = $args['layout']; 889 } 890 else { 891 $layout = 'default'; 892 } 893 894 $formFile = false; 895 896 // Check for the layout XML file. Use standard xml file if it exists. 897 $path = JPath::clean($base.'/views/'.$view.'/tmpl/'.$layout.'.xml'); 898 if (JFile::exists($path)) { 899 $formFile = $path; 900 } 901 902 // if custom layout, get the xml file from the template folder 903 // template folder is first part of file name -- template:folder 904 if (!$formFile && (strpos($layout, ':') > 0 )) 905 { 906 $temp = explode(':', $layout); 907 $templatePath = JPATH::clean(JPATH_SITE.'/templates/'.$temp[0].'/html/'.$option.'/'.$view.'/'.$temp[1].'.xml'); 908 if (JFile::exists($templatePath)) 909 { 910 $formFile = $templatePath; 911 } 912 } 913 } 914 915 //Now check for a view manifest file 916 if (!$formFile) 917 { 918 if (isset($view) && JFile::exists($path = JPath::clean($base.'/views/'.$view.'/metadata.xml'))) 919 { 920 $formFile = $path; 921 } 922 else 923 { 924 //Now check for a component manifest file 925 $path = JPath::clean($base.'/metadata.xml'); 926 if (JFile::exists($path)) 927 { 928 $formFile = $path; 929 } 930 } 931 } 932 } 933 934 if ($formFile) { 935 // If an XML file was found in the component, load it first. 936 // We need to qualify the full path to avoid collisions with component file names. 937 938 if ($form->loadFile($formFile, true, '/metadata') == false) { 939 throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); 940 } 941 942 // Attempt to load the xml file. 943 if (!$xml = simplexml_load_file($formFile)) { 944 throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); 945 } 946 947 // Get the help data from the XML file if present. 948 $help = $xml->xpath('/metadata/layout/help'); 949 if (!empty($help)) { 950 $helpKey = trim((string) $help[0]['key']); 951 $helpURL = trim((string) $help[0]['url']); 952 $helpLoc = trim((string) $help[0]['local']); 953 954 $this->helpKey = $helpKey ? $helpKey : $this->helpKey; 955 $this->helpURL = $helpURL ? $helpURL : $this->helpURL; 956 $this->helpLocal = (($helpLoc == 'true') || ($helpLoc == '1') || ($helpLoc == 'local')) ? true : false; 957 } 958 959 } 960 961 // Now load the component params. 962 // TODO: Work out why 'fixing' this breaks JForm 963 if ($isNew = false) { 964 $path = JPath::clean(JPATH_ADMINISTRATOR.'/components/'.$option.'/config.xml'); 965 } 966 else { 967 $path='null'; 968 } 969 970 if (JFile::exists($path)) { 971 // Add the component params last of all to the existing form. 972 if (!$form->load($path, true, '/config')) { 973 throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); 974 } 975 } 976 977 978 // Load the specific type file 979 if (!$form->loadFile('item_'.$type, false, false)) { 980 throw new Exception(JText::_('JERROR_LOADFILE_FAILED')); 981 } 982 983 // Association menu items 984 if (JFactory::getApplication()->get('menu_associations', 0)) { 985 $languages = JLanguageHelper::getLanguages('lang_code'); 986 987 $addform = new JXMLElement('<form />'); 988 $fields = $addform->addChild('fields'); 989 $fields->addAttribute('name', 'associations'); 990 $fieldset = $fields->addChild('fieldset'); 991 $fieldset->addAttribute('name', 'item_associations'); 992 $fieldset->addAttribute('description', 'COM_MENUS_ITEM_ASSOCIATIONS_FIELDSET_DESC'); 993 $add = false; 994 foreach ($languages as $tag => $language) 995 { 996 if ($tag != $data['language']) { 997 $add = true; 998 $field = $fieldset->addChild('field'); 999 $field->addAttribute('name', $tag); 1000 $field->addAttribute('type', 'menuitem'); 1001 $field->addAttribute('language', $tag); 1002 $field->addAttribute('label', $language->title); 1003 $field->addAttribute('translate_label', 'false'); 1004 $option = $field->addChild('option', 'COM_MENUS_ITEM_FIELD_ASSOCIATION_NO_VALUE'); 1005 $option->addAttribute('value', ''); 1006 } 1007 } 1008 if ($add) { 1009 $form->load($addform, false); 1010 } 1011 } 1012 1013 // Trigger the default form events. 1014 parent::preprocessForm($form, $data, $group); 1015 } 1016 1017 /** 1018 * Method rebuild the entire nested set tree. 1019 * 1020 * @return boolean False on failure or error, true otherwise. 1021 * @since 1.6 1022 */ 1023 public function rebuild() 1024 { 1025 // Initialiase variables. 1026 $db = $this->getDbo(); 1027 $table = $this->getTable(); 1028 1029 if (!$table->rebuild()) { 1030 $this->setError($table->getError()); 1031 return false; 1032 } 1033 1034 // Convert the parameters not in JSON format. 1035 $db->setQuery( 1036 'SELECT id, params' . 1037 ' FROM #__menu' . 1038 ' WHERE params NOT LIKE '.$db->quote('{%') . 1039 ' AND params <> '.$db->quote('') 1040 ); 1041 1042 $items = $db->loadObjectList(); 1043 if ($error = $db->getErrorMsg()) { 1044 $this->setError($error); 1045 return false; 1046 } 1047 1048 foreach ($items as &$item) 1049 { 1050 $registry = new JRegistry; 1051 $registry->loadString($item->params); 1052 $params = (string)$registry; 1053 1054 $db->setQuery( 1055 'UPDATE #__menu' . 1056 ' SET params = '.$db->quote($params). 1057 ' WHERE id = '.(int) $item->id 1058 ); 1059 if (!$db->query()) { 1060 $this->setError($error); 1061 return false; 1062 } 1063 1064 unset($registry); 1065 } 1066 1067 // Clean the cache 1068 $this->cleanCache(); 1069 1070 return true; 1071 } 1072 1073 /** 1074 * Method to save the form data. 1075 * 1076 * @param array $data The form data. 1077 * 1078 * @return boolean True on success. 1079 * @since 1.6 1080 */ 1081 public function save($data) 1082 { 1083 // Initialise variables. 1084 $pk = (!empty($data['id'])) ? $data['id'] : (int)$this->getState('item.id'); 1085 $isNew = true; 1086 $db = $this->getDbo(); 1087 $table = $this->getTable(); 1088 1089 // Load the row if saving an existing item. 1090 if ($pk > 0) { 1091 $table->load($pk); 1092 $isNew = false; 1093 } 1094 if (!$isNew && $table->menutype == $data['menutype']) { 1095 if ($table->parent_id == $data['parent_id'] ) { 1096 1097 // If first is chosen make the item the first child of the selected parent. 1098 if ($data['menuordering'] == -1) { 1099 $table->setLocation($data['parent_id'], 'first-child'); 1100 } 1101 // If last is chosen make it the last child of the selected parent. 1102 elseif ($data['menuordering'] == -2) { 1103 $table->setLocation($data['parent_id'], 'last-child'); 1104 } 1105 // Don't try to put an item after itself. All other ones put after the selected item. 1106 // $data['id'] is empty means it's a save as copy 1107 elseif ($data['menuordering'] && $table->id != $data['menuordering'] || empty($data['id'])) 1108 { 1109 $table->setLocation($data['menuordering'], 'after'); 1110 } 1111 // Just leave it where it is if no change is made. 1112 elseif ( $data['menuordering'] && $table->id == $data['menuordering']) 1113 { 1114 unset( $data['menuordering']); 1115 } 1116 } 1117 // Set the new parent id if parent id not matched and put in last position 1118 else { 1119 $table->setLocation($data['parent_id'], 'last-child'); 1120 1121 } 1122 } 1123 // We have a new item, so it is not a change. 1124 elseif ($isNew) { 1125 $table->setLocation($data['parent_id'], 'last-child'); 1126 } 1127 // The menu type has changed so we need to just put this at the bottom 1128 // of the root level. 1129 else { 1130 $table->setLocation(1, 'last-child'); 1131 } 1132 1133 // Bind the data. 1134 if (!$table->bind($data)) { 1135 $this->setError($table->getError()); 1136 return false; 1137 } 1138 1139 // Alter the title & alias for save as copy. Also, unset the home record. 1140 if(!$isNew && $data['id'] == 0){ 1141 list($title, $alias) = $this->generateNewTitle($table->parent_id, $table->alias, $table->title); 1142 $table->title = $title; 1143 $table->alias = $alias; 1144 $table->home = 0; 1145 } 1146 1147 // Check the data. 1148 if (!$table->check()) { 1149 $this->setError($table->getError()); 1150 return false; 1151 } 1152 1153 // Store the data. 1154 if (!$table->store()) { 1155 $this->setError($table->getError()); 1156 return false; 1157 } 1158 1159 // Rebuild the tree path. 1160 if (!$table->rebuildPath($table->id)) { 1161 $this->setError($table->getError()); 1162 return false; 1163 } 1164 1165 $this->setState('item.id', $table->id); 1166 $this->setState('item.menutype', $table->menutype); 1167 1168 // Load associated menu items 1169 if (JFactory::getApplication()->get('menu_associations', 0)) { 1170 // Adding self to the association 1171 $associations = $data['associations']; 1172 foreach ($associations as $tag=>$id) { 1173 if (empty($id)) { 1174 unset($associations[$tag]); 1175 } 1176 } 1177 1178 // Detecting all item menus 1179 $all_language = $table->language == '*'; 1180 if ($all_language && !empty($associations)) { 1181 JError::raiseNotice(403, JText::_('COM_MENUS_ERROR_ALL_LANGUAGE_ASSOCIATED')); 1182 } 1183 1184 $associations[$table->language]=$table->id; 1185 1186 // Deleting old association for these items 1187 $db = JFactory::getDbo(); 1188 $query = $db->getQuery(true); 1189 $query->delete('#__associations'); 1190 $query->where('context='.$db->quote('com_menus.item')); 1191 $query->where('id IN ('.implode(',', $associations).')'); 1192 $db->setQuery($query); 1193 $db->query(); 1194 if ($error = $db->getErrorMsg()) { 1195 $this->setError($error); 1196 return false; 1197 } 1198 1199 if (!$all_language && count($associations)>1) { 1200 // Adding new association for these items 1201 $key = md5(json_encode($associations)); 1202 $query->clear(); 1203 $query->insert('#__associations'); 1204 foreach ($associations as $tag=>$id) { 1205 $query->values($id.','.$db->quote('com_menus.item').','.$db->quote($key)); 1206 } 1207 $db->setQuery($query); 1208 $db->query(); 1209 if ($error = $db->getErrorMsg()) { 1210 $this->setError($error); 1211 return false; 1212 } 1213 } 1214 } 1215 1216 // Clean the cache 1217 $this->cleanCache(); 1218 1219 if (isset($data['link'])) { 1220 $base = JURI::base(); 1221 $juri = JURI::getInstance($base.$data['link']); 1222 $option = $juri->getVar('option'); 1223 1224 // Clean the cache 1225 parent::cleanCache($option); 1226 } 1227 1228 return true; 1229 } 1230 1231 /** 1232 * Method to save the reordered nested set tree. 1233 * First we save the new order values in the lft values of the changed ids. 1234 * Then we invoke the table rebuild to implement the new ordering. 1235 * 1236 * @param array $idArray id's of rows to be reordered 1237 * @param array $lft_array lft values of rows to be reordered 1238 * 1239 * @return boolean false on failuer or error, true otherwise 1240 * @since 1.6 1241 */ 1242 public function saveorder($idArray = null, $lft_array = null) 1243 { 1244 // Get an instance of the table object. 1245 $table = $this->getTable(); 1246 1247 if (!$table->saveorder($idArray, $lft_array)) { 1248 $this->setError($table->getError()); 1249 return false; 1250 } 1251 1252 // Clean the cache 1253 $this->cleanCache(); 1254 1255 return true; 1256 } 1257 1258 /** 1259 * Method to change the home state of one or more items. 1260 * 1261 * @param array $pks A list of the primary keys to change. 1262 * @param int $value The value of the home state. 1263 * 1264 * @return boolean True on success. 1265 * @since 1.6 1266 */ 1267 function setHome(&$pks, $value = 1) 1268 { 1269 // Initialise variables. 1270 $table = $this->getTable(); 1271 $pks = (array) $pks; 1272 $user = JFactory::getUser(); 1273 1274 $languages = array(); 1275 $onehome = false; 1276 1277 // Remember that we can set a home page for different languages, 1278 // so we need to loop through the primary key array. 1279 foreach ($pks as $i => $pk) 1280 { 1281 if ($table->load($pk)) { 1282 if (!array_key_exists($table->language, $languages)) { 1283 $languages[$table->language] = true; 1284 1285 if ($table->home == $value) { 1286 unset($pks[$i]); 1287 JError::raiseNotice(403, JText::_('COM_MENUS_ERROR_ALREADY_HOME')); 1288 } 1289 else { 1290 $table->home = $value; 1291 if ($table->language == '*') { 1292 $table->published = 1; 1293 } 1294 1295 if (!$this->canSave($table)) { 1296 // Prune items that you can't change. 1297 unset($pks[$i]); 1298 JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED')); 1299 } 1300 elseif (!$table->check()) { 1301 // Prune the items that failed pre-save checks. 1302 unset($pks[$i]); 1303 JError::raiseWarning(403, $table->getError()); 1304 } 1305 elseif (!$table->store()) { 1306 // Prune the items that could not be stored. 1307 unset($pks[$i]); 1308 JError::raiseWarning(403, $table->getError()); 1309 } 1310 } 1311 } 1312 else { 1313 unset($pks[$i]); 1314 if (!$onehome) { 1315 $onehome = true; 1316 JError::raiseNotice(403, JText::sprintf('COM_MENUS_ERROR_ONE_HOME')); 1317 } 1318 } 1319 } 1320 } 1321 1322 // Clean the cache 1323 $this->cleanCache(); 1324 1325 return true; 1326 } 1327 1328 /** 1329 * Method to change the published state of one or more records. 1330 * 1331 * @param array $pks A list of the primary keys to change. 1332 * @param int $value The value of the published state. 1333 * 1334 * @return boolean True on success. 1335 * @since 1.6 1336 */ 1337 function publish(&$pks, $value = 1) 1338 { 1339 // Initialise variables. 1340 $table = $this->getTable(); 1341 $pks = (array) $pks; 1342 1343 // Default menu item existence checks. 1344 if ($value != 1) { 1345 foreach ($pks as $i => $pk) 1346 { 1347 if ($table->load($pk) && $table->home && $table->language == '*') { 1348 // Prune items that you can't change. 1349 JError::raiseWarning(403, JText::_('JLIB_DATABASE_ERROR_MENU_UNPUBLISH_DEFAULT_HOME')); 1350 unset($pks[$i]); 1351 break; 1352 } 1353 } 1354 } 1355 1356 // Clean the cache 1357 $this->cleanCache(); 1358 1359 return parent::publish($pks, $value); 1360 } 1361 1362 /** 1363 * Method to change the title & alias. 1364 * 1365 * @param integer $parent_id The id of the parent. 1366 * @param string $alias The alias. 1367 * @param string $title The title. 1368 * 1369 * @return array Contains the modified title and alias. 1370 * 1371 * @since 1.6 1372 */ 1373 protected function generateNewTitle($parent_id, $alias, $title) 1374 { 1375 // Alter the title & alias 1376 $table = $this->getTable(); 1377 while ($table->load(array('alias' => $alias, 'parent_id' => $parent_id))) 1378 { 1379 $title = JString::increment($title); 1380 $alias = JString::increment($alias, 'dash'); 1381 } 1382 1383 return array($title, $alias); 1384 } 1385 1386 /** 1387 * Custom clean cache method 1388 * 1389 * @since 1.6 1390 */ 1391 protected function cleanCache($group = null, $client_id = 0) 1392 { 1393 parent::cleanCache('com_modules'); 1394 parent::cleanCache('mod_menu'); 1395 } 1396 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Tue Apr 3 11:40:28 2012 | Cross-referenced by PHPXref 0.7.1 |