[ Index ]

PHP Cross Reference of Joomla 2.5.4 DE

title

Body

[close]

/administrator/components/com_menus/models/ -> item.php (source)

   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  }


Generated: Tue Apr 3 11:40:28 2012 Cross-referenced by PHPXref 0.7.1