Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
admin.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Legacy
4  * @subpackage Model
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * Prototype admin model.
14  *
15  * @package Joomla.Legacy
16  * @subpackage Model
17  * @since 12.2
18  */
19 abstract class JModelAdmin extends JModelForm
20 {
21  /**
22  * The prefix to use with controller messages.
23  *
24  * @var string
25  * @since 12.2
26  */
27  protected $text_prefix = null;
28 
29  /**
30  * The event to trigger after deleting the data.
31  *
32  * @var string
33  * @since 12.2
34  */
35  protected $event_after_delete = null;
36 
37  /**
38  * The event to trigger after saving the data.
39  *
40  * @var string
41  * @since 12.2
42  */
43  protected $event_after_save = null;
44 
45  /**
46  * The event to trigger before deleting the data.
47  *
48  * @var string
49  * @since 12.2
50  */
51  protected $event_before_delete = null;
52 
53  /**
54  * The event to trigger before saving the data.
55  *
56  * @var string
57  * @since 12.2
58  */
59  protected $event_before_save = null;
60 
61  /**
62  * The event to trigger after changing the published state of the data.
63  *
64  * @var string
65  * @since 12.2
66  */
67  protected $event_change_state = null;
68 
69  /**
70  * Constructor.
71  *
72  * @param array $config An optional associative array of configuration settings.
73  *
74  * @see JModelLegacy
75  * @since 12.2
76  */
77  public function __construct($config = array())
78  {
79  parent::__construct($config);
80 
81  if (isset($config['event_after_delete']))
82  {
83  $this->event_after_delete = $config['event_after_delete'];
84  }
85  elseif (empty($this->event_after_delete))
86  {
87  $this->event_after_delete = 'onContentAfterDelete';
88  }
89 
90  if (isset($config['event_after_save']))
91  {
92  $this->event_after_save = $config['event_after_save'];
93  }
94  elseif (empty($this->event_after_save))
95  {
96  $this->event_after_save = 'onContentAfterSave';
97  }
98 
99  if (isset($config['event_before_delete']))
100  {
101  $this->event_before_delete = $config['event_before_delete'];
102  }
103  elseif (empty($this->event_before_delete))
104  {
105  $this->event_before_delete = 'onContentBeforeDelete';
106  }
107 
108  if (isset($config['event_before_save']))
109  {
110  $this->event_before_save = $config['event_before_save'];
111  }
112  elseif (empty($this->event_before_save))
113  {
114  $this->event_before_save = 'onContentBeforeSave';
115  }
116 
117  if (isset($config['event_change_state']))
118  {
119  $this->event_change_state = $config['event_change_state'];
120  }
121  elseif (empty($this->event_change_state))
122  {
123  $this->event_change_state = 'onContentChangeState';
124  }
125 
126  // Guess the JText message prefix. Defaults to the option.
127  if (isset($config['text_prefix']))
128  {
129  $this->text_prefix = strtoupper($config['text_prefix']);
130  }
131  elseif (empty($this->text_prefix))
132  {
133  $this->text_prefix = strtoupper($this->option);
134  }
135  }
136 
137  /**
138  * Method to perform batch operations on an item or a set of items.
139  *
140  * @param array $commands An array of commands to perform.
141  * @param array $pks An array of item ids.
142  * @param array $contexts An array of item contexts.
143  *
144  * @return boolean Returns true on success, false on failure.
145  *
146  * @since 12.2
147  */
148  public function batch($commands, $pks, $contexts)
149  {
150  // Sanitize ids.
151  $pks = array_unique($pks);
153 
154  // Remove any values of zero.
155  if (array_search(0, $pks, true))
156  {
157  unset($pks[array_search(0, $pks, true)]);
158  }
159 
160  if (empty($pks))
161  {
162  $this->setError(JText::_('JGLOBAL_NO_ITEM_SELECTED'));
163 
164  return false;
165  }
166 
167  $done = false;
168 
169  // Set some needed variables.
170  $this->user = JFactory::getUser();
171  $this->table = $this->getTable();
172  $this->tableClassName = get_class($this->table);
173  $this->contentType = new JUcmType;
174  $this->type = $this->contentType->getTypeByTable($this->tableClassName);
175  $this->batchSet = true;
176 
177  if ($this->type == false)
178  {
179  $type = new JUcmType;
180  $this->type = $type->getTypeByAlias($this->typeAlias);
181 
182  }
183  if ($this->type === false)
184  {
185  $type = new JUcmType;
186  $this->type = $type->getTypeByAlias($this->typeAlias);
187  $typeAlias = $this->type->type_alias;
188  }
189  else
190  {
191  $typeAlias = $this->type->type_alias;
192  }
193  $this->tagsObserver = $this->table->getObserverOfClass('JTableObserverTags');
194 
195  if (!empty($commands['category_id']))
196  {
197  $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c');
198 
199  if ($cmd == 'c')
200  {
201  $result = $this->batchCopy($commands['category_id'], $pks, $contexts);
202 
203  if (is_array($result))
204  {
205  $pks = $result;
206  }
207  else
208  {
209  return false;
210  }
211  }
212  elseif ($cmd == 'm' && !$this->batchMove($commands['category_id'], $pks, $contexts))
213  {
214  return false;
215  }
216 
217  $done = true;
218  }
219 
220  if (!empty($commands['assetgroup_id']))
221  {
222  if (!$this->batchAccess($commands['assetgroup_id'], $pks, $contexts))
223  {
224  return false;
225  }
226 
227  $done = true;
228  }
229 
230  if (!empty($commands['language_id']))
231  {
232  if (!$this->batchLanguage($commands['language_id'], $pks, $contexts))
233  {
234  return false;
235  }
236 
237  $done = true;
238  }
239 
240  if (!empty($commands['tag']))
241  {
242  if (!$this->batchTag($commands['tag'], $pks, $contexts))
243  {
244  return false;
245  }
246 
247  $done = true;
248  }
249 
250  if (!$done)
251  {
252  $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION'));
253  return false;
254  }
255 
256  // Clear the cache
257  $this->cleanCache();
258 
259  return true;
260  }
261 
262  /**
263  * Batch access level changes for a group of rows.
264  *
265  * @param integer $value The new value matching an Asset Group ID.
266  * @param array $pks An array of row IDs.
267  * @param array $contexts An array of item contexts.
268  *
269  * @return boolean True if successful, false otherwise and internal error is set.
270  *
271  * @since 12.2
272  */
273  protected function batchAccess($value, $pks, $contexts)
274  {
275  if (!$this->batchSet)
276  {
277  // Set some needed variables.
278  $this->user = JFactory::getUser();
279  $this->table = $this->getTable();
280  $this->tableClassName = get_class($this->table);
281  $this->contentType = new JUcmType;
282  $this->type = $this->contentType->getTypeByTable($this->tableClassName);
283  }
284 
285  foreach ($pks as $pk)
286  {
287  if ($this->user->authorise('core.edit', $contexts[$pk]))
288  {
289  $this->table->reset();
290  $this->table->load($pk);
291  $this->table->access = (int) $value;
292 
293  static::createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table);
294 
295  if (!$this->table->store())
296  {
297  $this->setError($table->getError());
298 
299  return false;
300  }
301  }
302  else
303  {
304  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
305 
306  return false;
307  }
308  }
309 
310  // Clean the cache
311  $this->cleanCache();
312 
313  return true;
314  }
315 
316  /**
317  * Batch copy items to a new category or current.
318  *
319  * @param integer $value The new category.
320  * @param array $pks An array of row IDs.
321  * @param array $contexts An array of item contexts.
322  *
323  * @return mixed An array of new IDs on success, boolean false on failure.
324  *
325  * @since 12.2
326  */
327  protected function batchCopy($value, $pks, $contexts)
328  {
329  if (!$this->batchSet)
330  {
331  // Set some needed variables.
332  $this->user = JFactory::getUser();
333  $this->table = $this->getTable();
334  $this->tableClassName = get_class($this->table);
335  $this->contentType = new JUcmType;
336  $this->type = $this->contentType->getTypeByTable($this->tableClassName);
337  }
338 
339  $i = 0;
340 
341  $categoryId = $value;
342 
343  if (!static::checkCategoryId($categoryId))
344  {
345  return false;
346  }
347 
348  // Parent exists so let's proceed
349  while (!empty($pks))
350  {
351  // Pop the first ID off the stack
352  $pk = array_shift($pks);
353 
354  $this->table->reset();
355 
356  // Check that the row actually exists
357  if (!$this->table->load($pk))
358  {
359  if ($error = $this->table->getError())
360  {
361  // Fatal error
362  $this->setError($error);
363 
364  return false;
365  }
366  else
367  {
368  // Not fatal error
369  $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk));
370  continue;
371  }
372  }
373 
374  static::generateTitle($categoryId, $this->table);
375 
376  // Reset the ID because we are making a copy
377  $this->table->id = 0;
378 
379  // New category ID
380  $this->table->catid = $categoryId;
381 
382  // TODO: Deal with ordering?
383  // $this->table->ordering = 1;
384 
385  // Check the row.
386  if (!$this->table->check())
387  {
388  $this->setError($this->table->getError());
389 
390  return false;
391  }
392 
393  static::createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table);
394 
395  // Store the row.
396  if (!$this->table->store())
397  {
398  $this->setError($table->getError());
399 
400  return false;
401  }
402 
403  // Get the new item ID
404  $newId = $this->table->get('id');
405 
406  // Add the new ID to the array
407  $newIds[$i] = $newId;
408  $i++;
409  }
410 
411  // Clean the cache
412  $this->cleanCache();
413 
414  return $newIds;
415  }
416 
417  /**
418  * Batch language changes for a group of rows.
419  *
420  * @param string $value The new value matching a language.
421  * @param array $pks An array of row IDs.
422  * @param array $contexts An array of item contexts.
423  *
424  * @return boolean True if successful, false otherwise and internal error is set.
425  *
426  * @since 11.3
427  */
428  protected function batchLanguage($value, $pks, $contexts)
429  {
430  if (!$this->batchSet)
431  {
432  // Set some needed variables.
433  $this->user = JFactory::getUser();
434  $this->table = $this->getTable();
435  $this->tableClassName = get_class($this->table);
436  $this->contentType = new JUcmType;
437  $this->type = $this->contentType->getTypeByTable($this->tableClassName);
438  }
439 
440  foreach ($pks as $pk)
441  {
442  if ($this->user->authorise('core.edit', $contexts[$pk]))
443  {
444  $this->table->reset();
445  $this->table->load($pk);
446  $this->table->language = $value;
447 
448  static::createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table);
449 
450  if (!$this->table->store())
451  {
452  $this->setError($this->table->getError());
453 
454  return false;
455  }
456  }
457  else
458  {
459  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
460 
461  return false;
462  }
463  }
464 
465  // Clean the cache
466  $this->cleanCache();
467 
468  return true;
469  }
470 
471  /**
472  * Batch move items to a new category
473  *
474  * @param integer $value The new category ID.
475  * @param array $pks An array of row IDs.
476  * @param array $contexts An array of item contexts.
477  *
478  * @return boolean True if successful, false otherwise and internal error is set.
479  *
480  * @since 12.2
481  */
482  protected function batchMove($value, $pks, $contexts)
483  {
484  if (!$this->batchSet)
485  {
486  // Set some needed variables.
487  $this->user = JFactory::getUser();
488  $this->table = $this->getTable();
489  $this->tableClassName = get_class($this->table);
490  $this->contentType = new JUcmType;
491  $this->type = $this->contentType->getTypeByTable($this->tableClassName);
492  }
493 
494  $categoryId = (int) $value;
495 
496  if (!static::checkCategoryId($categoryId))
497  {
498  return false;
499  }
500 
501  // Parent exists so we proceed
502  foreach ($pks as $pk)
503  {
504  if (!$this->user->authorise('core.edit', $contexts[$pk]))
505  {
506  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
507 
508  return false;
509  }
510 
511  // Check that the row actually exists
512  if (!$this->table->load($pk))
513  {
514  if ($error = $this->table->getError())
515  {
516  // Fatal error
517  $this->setError($error);
518 
519  return false;
520  }
521  else
522  {
523  // Not fatal error
524  $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk));
525  continue;
526  }
527  }
528 
529  // Set the new category ID
530  $this->table->catid = $categoryId;
531 
532  // Check the row.
533  if (!$this->table->check())
534  {
535  $this->setError($this->table->getError());
536 
537  return false;
538  }
539 
540  static::createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table);
541 
542  // Store the row.
543  if (!$this->table->store())
544  {
545  $this->setError($this->table->getError());
546 
547  return false;
548  }
549  }
550 
551  // Clean the cache
552  $this->cleanCache();
553 
554  return true;
555  }
556 
557  /**
558  * Batch tag a list of item.
559  *
560  * @param integer $value The value of the new tag.
561  * @param array $pks An array of row IDs.
562  * @param array $contexts An array of item contexts.
563  *
564  * @return void.
565  *
566  * @since 3.1
567  */
568  protected function batchTag($value, $pks, $contexts)
569  {
570  // Set the variables
571  $user = JFactory::getUser();
572  $table = $this->getTable();
573 
574  foreach ($pks as $pk)
575  {
576  if ($user->authorise('core.edit', $contexts[$pk]))
577  {
578  $table->reset();
579  $table->load($pk);
580  $tags = array($value);
581 
582  /**
583  * @var JTableObserverTags $tagsObserver
584  */
585  $tagsObserver = $table->getObserverOfClass('JTableObserverTags');
586  $result = $tagsObserver->setNewTags($tags, false);
587 
588  if (!$result)
589  {
590  $this->setError($table->getError());
591 
592  return false;
593  }
594  }
595  else
596  {
597  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
598 
599  return false;
600  }
601  }
602 
603  // Clean the cache
604  $this->cleanCache();
605 
606  return true;
607  }
608 
609  /**
610  * Method to test whether a record can be deleted.
611  *
612  * @param object $record A record object.
613  *
614  * @return boolean True if allowed to delete the record. Defaults to the permission for the component.
615  *
616  * @since 12.2
617  */
618  protected function canDelete($record)
619  {
620  $user = JFactory::getUser();
621 
622  return $user->authorise('core.delete', $this->option);
623  }
624 
625  /**
626  * Method to test whether a record can be deleted.
627  *
628  * @param object $record A record object.
629  *
630  * @return boolean True if allowed to change the state of the record. Defaults to the permission for the component.
631  *
632  * @since 12.2
633  */
634  protected function canEditState($record)
635  {
636  $user = JFactory::getUser();
637 
638  return $user->authorise('core.edit.state', $this->option);
639  }
640 
641  /**
642  * Method override to check-in a record or an array of record
643  *
644  * @param mixed $pks The ID of the primary key or an array of IDs
645  *
646  * @return mixed Boolean false if there is an error, otherwise the count of records checked in.
647  *
648  * @since 12.2
649  */
650  public function checkin($pks = array())
651  {
652  $pks = (array) $pks;
653  $table = $this->getTable();
654  $count = 0;
655 
656  if (empty($pks))
657  {
658  $pks = array((int) $this->getState($this->getName() . '.id'));
659  }
660 
661  // Check in all items.
662  foreach ($pks as $pk)
663  {
664  if ($table->load($pk))
665  {
666 
667  if ($table->checked_out > 0)
668  {
669  if (!parent::checkin($pk))
670  {
671  return false;
672  }
673  $count++;
674  }
675  }
676  else
677  {
678  $this->setError($table->getError());
679 
680  return false;
681  }
682  }
683 
684  return $count;
685  }
686 
687  /**
688  * Method override to check-out a record.
689  *
690  * @param integer $pk The ID of the primary key.
691  *
692  * @return boolean True if successful, false if an error occurs.
693  *
694  * @since 12.2
695  */
696  public function checkout($pk = null)
697  {
698  $pk = (!empty($pk)) ? $pk : (int) $this->getState($this->getName() . '.id');
699 
700  return parent::checkout($pk);
701  }
702 
703  /**
704  * Method to delete one or more records.
705  *
706  * @param array &$pks An array of record primary keys.
707  *
708  * @return boolean True if successful, false if an error occurs.
709  *
710  * @since 12.2
711  */
712  public function delete(&$pks)
713  {
714  $dispatcher = JEventDispatcher::getInstance();
715  $pks = (array) $pks;
716  $table = $this->getTable();
717 
718  // Include the content plugins for the on delete events.
719  JPluginHelper::importPlugin('content');
720 
721  // Iterate the items to delete each one.
722  foreach ($pks as $i => $pk)
723  {
724 
725  if ($table->load($pk))
726  {
727 
728  if ($this->canDelete($table))
729  {
730 
731  $context = $this->option . '.' . $this->name;
732 
733  // Trigger the onContentBeforeDelete event.
734  $result = $dispatcher->trigger($this->event_before_delete, array($context, $table));
735 
736  if (in_array(false, $result, true))
737  {
738  $this->setError($table->getError());
739  return false;
740  }
741 
742  if (!$table->delete($pk))
743  {
744  $this->setError($table->getError());
745  return false;
746  }
747 
748  // Trigger the onContentAfterDelete event.
749  $dispatcher->trigger($this->event_after_delete, array($context, $table));
750 
751  }
752  else
753  {
754 
755  // Prune items that you can't change.
756  unset($pks[$i]);
757  $error = $this->getError();
758  if ($error)
759  {
760  JLog::add($error, JLog::WARNING, 'jerror');
761  return false;
762  }
763  else
764  {
765  JLog::add(JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), JLog::WARNING, 'jerror');
766  return false;
767  }
768  }
769 
770  }
771  else
772  {
773  $this->setError($table->getError());
774  return false;
775  }
776  }
777 
778  // Clear the component's cache
779  $this->cleanCache();
780 
781  return true;
782  }
783 
784  /**
785  * Method to change the title & alias.
786  *
787  * @param integer $category_id The id of the category.
788  * @param string $alias The alias.
789  * @param string $title The title.
790  *
791  * @return array Contains the modified title and alias.
792  *
793  * @since 12.2
794  */
795  protected function generateNewTitle($category_id, $alias, $title)
796  {
797  // Alter the title & alias
798  $table = $this->getTable();
799  while ($table->load(array('alias' => $alias, 'catid' => $category_id)))
800  {
801  $title = JString::increment($title);
802  $alias = JString::increment($alias, 'dash');
803  }
804 
805  return array($title, $alias);
806  }
807 
808  /**
809  * Method to get a single record.
810  *
811  * @param integer $pk The id of the primary key.
812  *
813  * @return mixed Object on success, false on failure.
814  *
815  * @since 12.2
816  */
817  public function getItem($pk = null)
818  {
819  $pk = (!empty($pk)) ? $pk : (int) $this->getState($this->getName() . '.id');
820  $table = $this->getTable();
821 
822  if ($pk > 0)
823  {
824  // Attempt to load the row.
825  $return = $table->load($pk);
826 
827  // Check for a table object error.
828  if ($return === false && $table->getError())
829  {
830  $this->setError($table->getError());
831  return false;
832  }
833  }
834 
835  // Convert to the JObject before adding other data.
836  $properties = $table->getProperties(1);
837  $item = JArrayHelper::toObject($properties, 'JObject');
838 
839  if (property_exists($item, 'params'))
840  {
841  $registry = new JRegistry;
842  $registry->loadString($item->params);
843  $item->params = $registry->toArray();
844  }
845 
846  return $item;
847  }
848 
849  /**
850  * A protected method to get a set of ordering conditions.
851  *
852  * @param JTable $table A JTable object.
853  *
854  * @return array An array of conditions to add to ordering queries.
855  *
856  * @since 12.2
857  */
858  protected function getReorderConditions($table)
859  {
860  return array();
861  }
862 
863  /**
864  * Stock method to auto-populate the model state.
865  *
866  * @return void
867  *
868  * @since 12.2
869  */
870  protected function populateState()
871  {
872  $table = $this->getTable();
873  $key = $table->getKeyName();
874 
875  // Get the pk of the record from the request.
876  $pk = JFactory::getApplication()->input->getInt($key);
877  $this->setState($this->getName() . '.id', $pk);
878 
879  // Load the parameters.
880  $value = JComponentHelper::getParams($this->option);
881  $this->setState('params', $value);
882  }
883 
884  /**
885  * Prepare and sanitise the table data prior to saving.
886  *
887  * @param JTable $table A reference to a JTable object.
888  *
889  * @return void
890  *
891  * @since 12.2
892  */
893  protected function prepareTable($table)
894  {
895  // Derived class will provide its own implementation if required.
896  }
897 
898  /**
899  * Method to change the published state of one or more records.
900  *
901  * @param array &$pks A list of the primary keys to change.
902  * @param integer $value The value of the published state.
903  *
904  * @return boolean True on success.
905  *
906  * @since 12.2
907  */
908  public function publish(&$pks, $value = 1)
909  {
910  $dispatcher = JEventDispatcher::getInstance();
911  $user = JFactory::getUser();
912  $table = $this->getTable();
913  $pks = (array) $pks;
914 
915  // Include the content plugins for the change of state event.
916  JPluginHelper::importPlugin('content');
917 
918  // Access checks.
919  foreach ($pks as $i => $pk)
920  {
921  $table->reset();
922 
923  if ($table->load($pk))
924  {
925  if (!$this->canEditState($table))
926  {
927  // Prune items that you can't change.
928  unset($pks[$i]);
929  JLog::add(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), JLog::WARNING, 'jerror');
930 
931  return false;
932  }
933  }
934  }
935 
936  // Attempt to change the state of the records.
937  if (!$table->publish($pks, $value, $user->get('id')))
938  {
939  $this->setError($table->getError());
940 
941  return false;
942  }
943 
944  $context = $this->option . '.' . $this->name;
945 
946  // Trigger the onContentChangeState event.
947  $result = $dispatcher->trigger($this->event_change_state, array($context, $pks, $value));
948 
949  if (in_array(false, $result, true))
950  {
951  $this->setError($table->getError());
952 
953  return false;
954  }
955 
956  // Clear the component's cache
957  $this->cleanCache();
958 
959  return true;
960  }
961 
962  /**
963  * Method to adjust the ordering of a row.
964  *
965  * Returns NULL if the user did not have edit
966  * privileges for any of the selected primary keys.
967  *
968  * @param integer $pks The ID of the primary key to move.
969  * @param integer $delta Increment, usually +1 or -1
970  *
971  * @return mixed False on failure or error, true on success, null if the $pk is empty (no items selected).
972  *
973  * @since 12.2
974  */
975  public function reorder($pks, $delta = 0)
976  {
977  $table = $this->getTable();
978  $pks = (array) $pks;
979  $result = true;
980 
981  $allowed = true;
982 
983  foreach ($pks as $i => $pk)
984  {
985  $table->reset();
986 
987  if ($table->load($pk) && $this->checkout($pk))
988  {
989  // Access checks.
990  if (!$this->canEditState($table))
991  {
992  // Prune items that you can't change.
993  unset($pks[$i]);
994  $this->checkin($pk);
995  JLog::add(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), JLog::WARNING, 'jerror');
996  $allowed = false;
997  continue;
998  }
999 
1000  $where = $this->getReorderConditions($table);
1001 
1002  if (!$table->move($delta, $where))
1003  {
1004  $this->setError($table->getError());
1005  unset($pks[$i]);
1006  $result = false;
1007  }
1008 
1009  $this->checkin($pk);
1010  }
1011  else
1012  {
1013  $this->setError($table->getError());
1014  unset($pks[$i]);
1015  $result = false;
1016  }
1017  }
1018 
1019  if ($allowed === false && empty($pks))
1020  {
1021  $result = null;
1022  }
1023 
1024  // Clear the component's cache
1025  if ($result == true)
1026  {
1027  $this->cleanCache();
1028  }
1029 
1030  return $result;
1031  }
1032 
1033  /**
1034  * Method to save the form data.
1035  *
1036  * @param array $data The form data.
1037  *
1038  * @return boolean True on success, False on error.
1039  *
1040  * @since 12.2
1041  */
1042  public function save($data)
1043  {
1044  $dispatcher = JEventDispatcher::getInstance();
1045  $table = $this->getTable();
1046 
1047  if ((!empty($data['tags']) && $data['tags'][0] != ''))
1048  {
1049  $table->newTags = $data['tags'];
1050  }
1051 
1052  $key = $table->getKeyName();
1053  $pk = (!empty($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id');
1054  $isNew = true;
1055 
1056  // Include the content plugins for the on save events.
1057  JPluginHelper::importPlugin('content');
1058 
1059  // Allow an exception to be thrown.
1060  try
1061  {
1062  // Load the row if saving an existing record.
1063  if ($pk > 0)
1064  {
1065  $table->load($pk);
1066  $isNew = false;
1067  }
1068 
1069  // Bind the data.
1070  if (!$table->bind($data))
1071  {
1072  $this->setError($table->getError());
1073 
1074  return false;
1075  }
1076 
1077  // Prepare the row for saving
1078  $this->prepareTable($table);
1079 
1080  // Check the data.
1081  if (!$table->check())
1082  {
1083  $this->setError($table->getError());
1084  return false;
1085  }
1086 
1087  // Trigger the onContentBeforeSave event.
1088  $result = $dispatcher->trigger($this->event_before_save, array($this->option . '.' . $this->name, $table, $isNew));
1089 
1090  if (in_array(false, $result, true))
1091  {
1092  $this->setError($table->getError());
1093  return false;
1094  }
1095 
1096  // Store the data.
1097  if (!$table->store())
1098  {
1099  $this->setError($table->getError());
1100  return false;
1101  }
1102 
1103  // Clean the cache.
1104  $this->cleanCache();
1105 
1106  // Trigger the onContentAfterSave event.
1107  $dispatcher->trigger($this->event_after_save, array($this->option . '.' . $this->name, $table, $isNew));
1108  }
1109  catch (Exception $e)
1110  {
1111  $this->setError($e->getMessage());
1112 
1113  return false;
1114  }
1115 
1116  $pkName = $table->getKeyName();
1117 
1118  if (isset($table->$pkName))
1119  {
1120  $this->setState($this->getName() . '.id', $table->$pkName);
1121  }
1122  $this->setState($this->getName() . '.new', $isNew);
1123 
1124  return true;
1125  }
1126 
1127  /**
1128  * Saves the manually set order of records.
1129  *
1130  * @param array $pks An array of primary key ids.
1131  * @param integer $order +1 or -1
1132  *
1133  * @return mixed
1134  *
1135  * @since 12.2
1136  */
1137  public function saveorder($pks = null, $order = null)
1138  {
1139  $table = $this->getTable();
1140  $tableClassName = get_class($table);
1141  $contentType = new JUcmType;
1142  $type = $contentType->getTypeByTable($tableClassName);
1143  $typeAlias = $type->type_alias;
1144  $tagsObserver = $table->getObserverOfClass('JTableObserverTags');
1145  $conditions = array();
1146 
1147  if (empty($pks))
1148  {
1149  return JError::raiseWarning(500, JText::_($this->text_prefix . '_ERROR_NO_ITEMS_SELECTED'));
1150  }
1151 
1152  // Update ordering values
1153  foreach ($pks as $i => $pk)
1154  {
1155  $table->load((int) $pk);
1156 
1157  // Access checks.
1158  if (!$this->canEditState($table))
1159  {
1160  // Prune items that you can't change.
1161  unset($pks[$i]);
1162  JLog::add(JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), JLog::WARNING, 'jerror');
1163  }
1164  elseif ($table->ordering != $order[$i])
1165  {
1166  $table->ordering = $order[$i];
1167 
1168  $this->createTagsHelper($tagsObserver, $type, $pk, $typeAlias, $table);
1169 
1170  if (!$table->store())
1171  {
1172  $this->setError($table->getError());
1173  return false;
1174  }
1175 
1176  // Remember to reorder within position and client_id
1177  $condition = $this->getReorderConditions($table);
1178  $found = false;
1179 
1180  foreach ($conditions as $cond)
1181  {
1182  if ($cond[1] == $condition)
1183  {
1184  $found = true;
1185  break;
1186  }
1187  }
1188 
1189  if (!$found)
1190  {
1191  $key = $table->getKeyName();
1192  $conditions[] = array($table->$key, $condition);
1193  }
1194  }
1195  }
1196 
1197  // Execute reorder for each category.
1198  foreach ($conditions as $cond)
1199  {
1200  $table->load($cond[0]);
1201  $table->reorder($cond[1]);
1202  }
1203 
1204  // Clear the component's cache
1205  $this->cleanCache();
1206 
1207  return true;
1208  }
1209 
1210  /**
1211  * Method to creat a tags helper to ensure proper management of tags
1212  *
1213  * @param JTableObserverTags $tagsObserver The tags observer for this table
1214  * @param JUcmType $type The type for the table being processed
1215  * @param integer $pk Primary key of the item bing processed
1216  * @param string $typeAlias The type alias for this table
1217  * @param JTable $table The JTable object
1218  *
1219  * @return void
1220  *
1221  * @since 3.2
1222  */
1223  public function createTagsHelper($tagsObserver, $type, $pk, $typeAlias, $table)
1224  {
1225  if (!empty($tagsObserver) && !empty($type))
1226  {
1227  $table->tagsHelper = new JHelperTags();
1228  $table->tagsHelper->typeAlias = $typeAlias;
1229  $table->tagsHelper->tags = explode(',', $table->tagsHelper->getTagIds($pk, $typeAlias));
1230  }
1231  }
1232 
1233  /**
1234  * Method to check the validity of the category ID for batch copy and move
1235  *
1236  * @param integer $categoryId The category ID to check
1237  *
1238  * @return boolean
1239  *
1240  * @since 3.2
1241  */
1242  protected function checkCategoryId($categoryId)
1243  {
1244  // Check that the category exists
1245  if ($categoryId)
1246  {
1247  $categoryTable = JTable::getInstance('Category');
1248 
1249  if (!$categoryTable->load($categoryId))
1250  {
1251  if ($error = $categoryTable->getError())
1252  {
1253  // Fatal error
1254  $this->setError($error);
1255  return false;
1256  }
1257  else
1258  {
1259  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
1260 
1261  return false;
1262  }
1263  }
1264  }
1265 
1266  if (empty($categoryId))
1267  {
1268  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
1269  return false;
1270  }
1271 
1272  // Check that the user has create permission for the component
1273  $extension = JFactory::getApplication()->input->get('option', '');
1274 
1275  if (!$this->user->authorise('core.create', $extension . '.category.' . $categoryId))
1276  {
1277  $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
1278 
1279  return false;
1280  }
1281 
1282  return true;
1283  }
1284 
1285  /**
1286  * A method to preprocess generating a new title in order to allow tables with alternative names
1287  * for alias and title to use the batch move and copy methods
1288  *
1289  * @param integer $categoryId The target category id
1290  * @param JTable $table The JTable within which move or copy is taking place
1291  *
1292  * @return void
1293  *
1294  * @since 3.2
1295  */
1296  public function generateTitle($categoryId, $table)
1297  {
1298  // Alter the title & alias
1299  $data = $this->generateNewTitle($categoryId, $table->alias, $table->title);
1300  $table->title = $data['0'];
1301  $table->alias = $data['1'];
1302  }
1303 }