PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/fof/model/model.php

https://github.com/J2MTecnologia/joomla-3.x
PHP | 3118 lines | 1690 code | 460 blank | 968 comment | 190 complexity | 46c8bb57ed41b0f6c9c23d8cc21e1934 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @package FrameworkOnFramework
  4. * @subpackage model
  5. * @copyright Copyright (C) 2010 - 2014 Akeeba Ltd. All rights reserved.
  6. * @license GNU General Public License version 2 or later; see LICENSE.txt
  7. */
  8. // Protect from unauthorized access
  9. defined('FOF_INCLUDED') or die;
  10. /**
  11. * FrameworkOnFramework Model class. The Model is the worhorse. It performs all
  12. * of the business logic based on its state and then returns the raw (processed)
  13. * data to the caller, or modifies its own state. It's important to note that
  14. * the model doesn't get data directly from the request (this is the
  15. * Controller's business) and that it doesn't output anything (that the View's
  16. * business).
  17. *
  18. * @package FrameworkOnFramework
  19. * @since 1.0
  20. */
  21. class FOFModel extends FOFUtilsObject
  22. {
  23. /**
  24. * Indicates if the internal state has been set
  25. *
  26. * @var boolean
  27. * @since 12.2
  28. */
  29. protected $__state_set = null;
  30. /**
  31. * Database Connector
  32. *
  33. * @var object
  34. * @since 12.2
  35. */
  36. protected $_db;
  37. /**
  38. * The event to trigger after deleting the data.
  39. * @var string
  40. */
  41. protected $event_after_delete = 'onContentAfterDelete';
  42. /**
  43. * The event to trigger after saving the data.
  44. * @var string
  45. */
  46. protected $event_after_save = 'onContentAfterSave';
  47. /**
  48. * The event to trigger before deleting the data.
  49. * @var string
  50. */
  51. protected $event_before_delete = 'onContentBeforeDelete';
  52. /**
  53. * The event to trigger before saving the data.
  54. * @var string
  55. */
  56. protected $event_before_save = 'onContentBeforeSave';
  57. /**
  58. * The event to trigger after changing the published state of the data.
  59. * @var string
  60. */
  61. protected $event_change_state = 'onContentChangeState';
  62. /**
  63. * The event to trigger when cleaning cache.
  64. *
  65. * @var string
  66. * @since 12.2
  67. */
  68. protected $event_clean_cache = null;
  69. /**
  70. * Stores a list of IDs passed to the model's state
  71. * @var array
  72. */
  73. protected $id_list = array();
  74. /**
  75. * The first row ID passed to the model's state
  76. * @var int
  77. */
  78. protected $id = null;
  79. /**
  80. * Input variables, passed on from the controller, in an associative array
  81. * @var array
  82. */
  83. protected $input = array();
  84. /**
  85. * The list of records made available through getList
  86. * @var array
  87. */
  88. protected $list = null;
  89. /**
  90. * The model (base) name
  91. *
  92. * @var string
  93. * @since 12.2
  94. */
  95. protected $name;
  96. /**
  97. * The URL option for the component.
  98. *
  99. * @var string
  100. * @since 12.2
  101. */
  102. protected $option = null;
  103. /**
  104. * The table object, populated when saving data
  105. * @var FOFTable
  106. */
  107. protected $otable = null;
  108. /**
  109. * Pagination object
  110. * @var JPagination
  111. */
  112. protected $pagination = null;
  113. /**
  114. * The table object, populated when retrieving data
  115. * @var FOFTable
  116. */
  117. protected $record = null;
  118. /**
  119. * A state object
  120. *
  121. * @var string
  122. * @since 12.2
  123. */
  124. protected $state;
  125. /**
  126. * The name of the table to use
  127. * @var string
  128. */
  129. protected $table = null;
  130. /**
  131. * Total rows based on the filters set in the model's state
  132. * @var int
  133. */
  134. protected $total = null;
  135. /**
  136. * Should I save the model's state in the session?
  137. * @var bool
  138. */
  139. protected $_savestate = null;
  140. /**
  141. * Array of form objects.
  142. *
  143. * @var array
  144. * @since 2.0
  145. */
  146. protected $_forms = array();
  147. /**
  148. * The data to load into a form
  149. *
  150. * @var array
  151. * @since 2.0
  152. */
  153. protected $_formData = array();
  154. /**
  155. * An instance of FOFConfigProvider to provision configuration overrides
  156. *
  157. * @var FOFConfigProvider
  158. */
  159. protected $configProvider = null;
  160. /**
  161. * FOFModelDispatcherBehavior for dealing with extra behaviors
  162. *
  163. * @var FOFModelDispatcherBehavior
  164. */
  165. protected $modelDispatcher = null;
  166. /**
  167. * Default behaviors to apply to the model
  168. *
  169. * @var array
  170. */
  171. protected $default_behaviors = array('filters');
  172. /**
  173. * Returns a new model object. Unless overriden by the $config array, it will
  174. * try to automatically populate its state from the request variables.
  175. *
  176. * @param string $type Model type, e.g. 'Items'
  177. * @param string $prefix Model prefix, e.g. 'FoobarModel'
  178. * @param array $config Model configuration variables
  179. *
  180. * @return FOFModel
  181. */
  182. public static function &getAnInstance($type, $prefix = '', $config = array())
  183. {
  184. // Make sure $config is an array
  185. if (is_object($config))
  186. {
  187. $config = (array) $config;
  188. }
  189. elseif (!is_array($config))
  190. {
  191. $config = array();
  192. }
  193. $type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type);
  194. $modelClass = $prefix . ucfirst($type);
  195. $result = false;
  196. // Guess the component name and include path
  197. if (!empty($prefix))
  198. {
  199. preg_match('/(.*)Model$/', $prefix, $m);
  200. $component = 'com_' . strtolower($m[1]);
  201. }
  202. else
  203. {
  204. $component = '';
  205. }
  206. if (array_key_exists('input', $config))
  207. {
  208. if (!($config['input'] instanceof FOFInput))
  209. {
  210. if (!is_array($config['input']))
  211. {
  212. $config['input'] = (array) $config['input'];
  213. }
  214. $config['input'] = array_merge($_REQUEST, $config['input']);
  215. $config['input'] = new FOFInput($config['input']);
  216. }
  217. }
  218. else
  219. {
  220. $config['input'] = new FOFInput;
  221. }
  222. if (empty($component))
  223. {
  224. $component = $config['input']->get('option', 'com_foobar');
  225. }
  226. $config['option'] = $component;
  227. $needsAView = true;
  228. if (array_key_exists('view', $config))
  229. {
  230. if (!empty($config['view']))
  231. {
  232. $needsAView = false;
  233. }
  234. }
  235. if ($needsAView)
  236. {
  237. $config['view'] = strtolower($type);
  238. }
  239. $config['input']->set('option', $config['option']);
  240. // Get the component directories
  241. $componentPaths = FOFPlatform::getInstance()->getComponentBaseDirs($component);
  242. $filesystem = FOFPlatform::getInstance()->getIntegrationObject('filesystem');
  243. // Try to load the requested model class
  244. if (!class_exists($modelClass))
  245. {
  246. $include_paths = self::addIncludePath();
  247. $extra_paths = array(
  248. $componentPaths['main'] . '/models',
  249. $componentPaths['alt'] . '/models'
  250. );
  251. $include_paths = array_merge($extra_paths, $include_paths);
  252. // Try to load the model file
  253. $path = $filesystem->pathFind(
  254. $include_paths, self::_createFileName('model', array('name' => $type))
  255. );
  256. if ($path)
  257. {
  258. require_once $path;
  259. }
  260. }
  261. // Fallback to the Default model class, e.g. FoobarModelDefault
  262. if (!class_exists($modelClass))
  263. {
  264. $modelClass = $prefix . 'Default';
  265. if (!class_exists($modelClass))
  266. {
  267. $include_paths = self::addIncludePath();
  268. $extra_paths = array(
  269. $componentPaths['main'] . '/models',
  270. $componentPaths['alt'] . '/models'
  271. );
  272. $include_paths = array_merge($extra_paths, $include_paths);
  273. // Try to load the model file
  274. $path = $filesystem->pathFind(
  275. $include_paths, self::_createFileName('model', array('name' => 'default'))
  276. );
  277. if ($path)
  278. {
  279. require_once $path;
  280. }
  281. }
  282. }
  283. // Fallback to the generic FOFModel model class
  284. if (!class_exists($modelClass))
  285. {
  286. $modelClass = 'FOFModel';
  287. }
  288. $result = new $modelClass($config);
  289. return $result;
  290. }
  291. /**
  292. * Adds a behavior to the model
  293. *
  294. * @param string $name The name of the behavior
  295. * @param array $config Optional Behavior configuration
  296. *
  297. * @return boolean True if the behavior is found and added
  298. */
  299. public function addBehavior($name, $config = array())
  300. {
  301. // Sanity check: this objects needs a non-null behavior handler
  302. if (!is_object($this->modelDispatcher))
  303. {
  304. return false;
  305. }
  306. // Sanity check: this objects needs a behavior handler of the correct class type
  307. if (!($this->modelDispatcher instanceof FOFModelDispatcherBehavior))
  308. {
  309. return false;
  310. }
  311. // First look for ComponentnameModelViewnameBehaviorName (e.g. FoobarModelItemsBehaviorFilter)
  312. $option_name = str_replace('com_', '', $this->option);
  313. $behaviorClass = ucfirst($option_name) . 'Model' . FOFInflector::pluralize($this->name) . 'Behavior' . ucfirst(strtolower($name));
  314. if (class_exists($behaviorClass))
  315. {
  316. $behavior = new $behaviorClass($this->modelDispatcher, $config);
  317. return true;
  318. }
  319. // Then look for ComponentnameModelBehaviorName (e.g. FoobarModelBehaviorFilter)
  320. $option_name = str_replace('com_', '', $this->option);
  321. $behaviorClass = ucfirst($option_name) . 'ModelBehavior' . ucfirst(strtolower($name));
  322. if (class_exists($behaviorClass))
  323. {
  324. $behavior = new $behaviorClass($this->modelDispatcher, $config);
  325. return true;
  326. }
  327. // Then look for FOFModelBehaviorName (e.g. FOFModelBehaviorFilter)
  328. $behaviorClassAlt = 'FOFModelBehavior' . ucfirst(strtolower($name));
  329. if (class_exists($behaviorClassAlt))
  330. {
  331. $behavior = new $behaviorClassAlt($this->modelDispatcher, $config);
  332. return true;
  333. }
  334. // Nothing found? Return false.
  335. return false;
  336. }
  337. /**
  338. * Returns a new instance of a model, with the state reset to defaults
  339. *
  340. * @param string $type Model type, e.g. 'Items'
  341. * @param string $prefix Model prefix, e.g. 'FoobarModel'
  342. * @param array $config Model configuration variables
  343. *
  344. * @return FOFModel
  345. */
  346. public static function &getTmpInstance($type, $prefix = '', $config = array())
  347. {
  348. // Make sure $config is an array
  349. if (is_object($config))
  350. {
  351. $config = (array) $config;
  352. }
  353. elseif (!is_array($config))
  354. {
  355. $config = array();
  356. }
  357. if (!array_key_exists('savesate', $config))
  358. {
  359. $config['savestate'] = false;
  360. }
  361. $ret = self::getAnInstance($type, $prefix, $config)
  362. ->getClone()
  363. ->clearState()
  364. ->clearInput()
  365. ->reset()
  366. ->savestate(0)
  367. ->limitstart(0)
  368. ->limit(0);
  369. return $ret;
  370. }
  371. /**
  372. * Add a directory where FOFModel should search for models. You may
  373. * either pass a string or an array of directories.
  374. *
  375. * @param mixed $path A path or array[sting] of paths to search.
  376. * @param string $prefix A prefix for models.
  377. *
  378. * @return array An array with directory elements. If prefix is equal to '', all directories are returned.
  379. *
  380. * @since 12.2
  381. */
  382. public static function addIncludePath($path = '', $prefix = '')
  383. {
  384. static $paths;
  385. if (!isset($paths))
  386. {
  387. $paths = array();
  388. }
  389. if (!isset($paths[$prefix]))
  390. {
  391. $paths[$prefix] = array();
  392. }
  393. if (!isset($paths['']))
  394. {
  395. $paths[''] = array();
  396. }
  397. if (!empty($path))
  398. {
  399. $filesystem = FOFPlatform::getInstance()->getIntegrationObject('filesystem');
  400. if (!in_array($path, $paths[$prefix]))
  401. {
  402. array_unshift($paths[$prefix], $filesystem->pathClean($path));
  403. }
  404. if (!in_array($path, $paths['']))
  405. {
  406. array_unshift($paths[''], $filesystem->pathClean($path));
  407. }
  408. }
  409. return $paths[$prefix];
  410. }
  411. /**
  412. * Adds to the stack of model table paths in LIFO order.
  413. *
  414. * @param mixed $path The directory as a string or directories as an array to add.
  415. *
  416. * @return void
  417. *
  418. * @since 12.2
  419. */
  420. public static function addTablePath($path)
  421. {
  422. FOFTable::addIncludePath($path);
  423. }
  424. /**
  425. * Create the filename for a resource
  426. *
  427. * @param string $type The resource type to create the filename for.
  428. * @param array $parts An associative array of filename information.
  429. *
  430. * @return string The filename
  431. *
  432. * @since 12.2
  433. */
  434. protected static function _createFileName($type, $parts = array())
  435. {
  436. $filename = '';
  437. switch ($type)
  438. {
  439. case 'model':
  440. $filename = strtolower($parts['name']) . '.php';
  441. break;
  442. }
  443. return $filename;
  444. }
  445. /**
  446. * Public class constructor
  447. *
  448. * @param array $config The configuration array
  449. */
  450. public function __construct($config = array())
  451. {
  452. // Make sure $config is an array
  453. if (is_object($config))
  454. {
  455. $config = (array) $config;
  456. }
  457. elseif (!is_array($config))
  458. {
  459. $config = array();
  460. }
  461. // Get the input
  462. if (array_key_exists('input', $config))
  463. {
  464. if ($config['input'] instanceof FOFInput)
  465. {
  466. $this->input = $config['input'];
  467. }
  468. else
  469. {
  470. $this->input = new FOFInput($config['input']);
  471. }
  472. }
  473. else
  474. {
  475. $this->input = new FOFInput;
  476. }
  477. // Load the configuration provider
  478. $this->configProvider = new FOFConfigProvider;
  479. // Load the behavior dispatcher
  480. $this->modelDispatcher = new FOFModelDispatcherBehavior;
  481. // Set the $name/$_name variable
  482. $component = $this->input->getCmd('option', 'com_foobar');
  483. if (array_key_exists('option', $config))
  484. {
  485. $component = $config['option'];
  486. }
  487. // Set the $name variable
  488. $this->input->set('option', $component);
  489. $component = $this->input->getCmd('option', 'com_foobar');
  490. if (array_key_exists('option', $config))
  491. {
  492. $component = $config['option'];
  493. }
  494. $this->input->set('option', $component);
  495. $bareComponent = str_replace('com_', '', strtolower($component));
  496. // Get the view name
  497. $className = get_class($this);
  498. if ($className == 'FOFModel')
  499. {
  500. if (array_key_exists('view', $config))
  501. {
  502. $view = $config['view'];
  503. }
  504. if (empty($view))
  505. {
  506. $view = $this->input->getCmd('view', 'cpanel');
  507. }
  508. }
  509. else
  510. {
  511. $eliminatePart = ucfirst($bareComponent) . 'Model';
  512. $view = strtolower(str_replace($eliminatePart, '', $className));
  513. }
  514. if (array_key_exists('name', $config))
  515. {
  516. $name = $config['name'];
  517. }
  518. else
  519. {
  520. $name = $view;
  521. }
  522. $this->name = $name;
  523. $this->option = $component;
  524. // Set the model state
  525. if (array_key_exists('state', $config))
  526. {
  527. $this->state = $config['state'];
  528. }
  529. else
  530. {
  531. $this->state = new FOFUtilsObject;
  532. }
  533. // Set the model dbo
  534. if (array_key_exists('dbo', $config))
  535. {
  536. $this->_db = $config['dbo'];
  537. }
  538. else
  539. {
  540. $this->_db = FOFPlatform::getInstance()->getDbo();
  541. }
  542. // Set the default view search path
  543. if (array_key_exists('table_path', $config))
  544. {
  545. $this->addTablePath($config['table_path']);
  546. }
  547. else
  548. {
  549. $componentPaths = FOFPlatform::getInstance()->getComponentBaseDirs($this->option);
  550. $path = $componentPaths['admin'] . '/tables';
  551. $altPath = $this->configProvider->get($this->option . '.views.' . FOFInflector::singularize($this->name) . '.config.table_path', null);
  552. if ($altPath)
  553. {
  554. $path = $componentPaths['main'] . '/' . $altPath;
  555. }
  556. $this->addTablePath($path);
  557. }
  558. // Assign the correct table
  559. if (array_key_exists('table', $config))
  560. {
  561. $this->table = $config['table'];
  562. }
  563. else
  564. {
  565. $table = $this->configProvider->get(
  566. $this->option . '.views.' . FOFInflector::singularize($this->name) .
  567. '.config.table', FOFInflector::singularize($view)
  568. );
  569. $this->table = $table;
  570. }
  571. // Set the internal state marker - used to ignore setting state from the request
  572. if (!empty($config['ignore_request']) || !is_null(
  573. $this->configProvider->get(
  574. $this->option . '.views.' . FOFInflector::singularize($this->name) .
  575. '.config.ignore_request', null
  576. )
  577. ))
  578. {
  579. $this->__state_set = true;
  580. }
  581. // Get and store the pagination request variables
  582. $defaultSaveState = array_key_exists('savestate', $config) ? $config['savestate'] : -999;
  583. $this->populateSavestate($defaultSaveState);
  584. if (FOFPlatform::getInstance()->isCli())
  585. {
  586. $limit = 20;
  587. $limitstart = 0;
  588. }
  589. else
  590. {
  591. $app = JFactory::getApplication();
  592. if (method_exists($app, 'getCfg'))
  593. {
  594. $default_limit = $app->getCfg('list_limit');
  595. }
  596. else
  597. {
  598. $default_limit = 20;
  599. }
  600. $limit = $this->getUserStateFromRequest($component . '.' . $view . '.limit', 'limit', $default_limit, 'int', $this->_savestate);
  601. $limitstart = $this->getUserStateFromRequest($component . '.' . $view . '.limitstart', 'limitstart', 0, 'int', $this->_savestate);
  602. }
  603. $this->setState('limit', $limit);
  604. $this->setState('limitstart', $limitstart);
  605. // Get the ID or list of IDs from the request or the configuration
  606. if (array_key_exists('cid', $config))
  607. {
  608. $cid = $config['cid'];
  609. }
  610. elseif ($cid = $this->configProvider->get(
  611. $this->option . '.views.' . FOFInflector::singularize($this->name) . '.config.cid', null
  612. )
  613. )
  614. {
  615. $cid = explode(',', $cid);
  616. }
  617. else
  618. {
  619. $cid = $this->input->get('cid', array(), 'array');
  620. }
  621. if (array_key_exists('id', $config))
  622. {
  623. $id = $config['id'];
  624. }
  625. elseif ($id = $this->configProvider->get(
  626. $this->option . '.views.' . FOFInflector::singularize($this->name) . '.config.id', null
  627. )
  628. )
  629. {
  630. $id = explode(',', $id);
  631. $id = array_shift($id);
  632. }
  633. else
  634. {
  635. $id = $this->input->getInt('id', 0);
  636. }
  637. if (is_array($cid) && !empty($cid))
  638. {
  639. $this->setIds($cid);
  640. }
  641. else
  642. {
  643. $this->setId($id);
  644. }
  645. // Populate the event names from the $config array
  646. $configKey = $this->option . '.views.' . FOFInflector::singularize($view) . '.config.';
  647. // Assign after delete event handler
  648. if (isset($config['event_after_delete']))
  649. {
  650. $this->event_after_delete = $config['event_after_delete'];
  651. }
  652. else
  653. {
  654. $this->event_after_delete = $this->configProvider->get(
  655. $configKey . 'event_after_delete',
  656. $this->event_after_delete
  657. );
  658. }
  659. // Assign after save event handler
  660. if (isset($config['event_after_save']))
  661. {
  662. $this->event_after_save = $config['event_after_save'];
  663. }
  664. else
  665. {
  666. $this->event_after_save = $this->configProvider->get(
  667. $configKey . 'event_after_save',
  668. $this->event_after_save
  669. );
  670. }
  671. // Assign before delete event handler
  672. if (isset($config['event_before_delete']))
  673. {
  674. $this->event_before_delete = $config['event_before_delete'];
  675. }
  676. else
  677. {
  678. $this->event_before_delete = $this->configProvider->get(
  679. $configKey . 'event_before_delete',
  680. $this->event_before_delete
  681. );
  682. }
  683. // Assign before save event handler
  684. if (isset($config['event_before_save']))
  685. {
  686. $this->event_before_save = $config['event_before_save'];
  687. }
  688. else
  689. {
  690. $this->event_before_save = $this->configProvider->get(
  691. $configKey . 'event_before_save',
  692. $this->event_before_save
  693. );
  694. }
  695. // Assign state change event handler
  696. if (isset($config['event_change_state']))
  697. {
  698. $this->event_change_state = $config['event_change_state'];
  699. }
  700. else
  701. {
  702. $this->event_change_state = $this->configProvider->get(
  703. $configKey . 'event_change_state',
  704. $this->event_change_state
  705. );
  706. }
  707. // Assign cache clean event handler
  708. if (isset($config['event_clean_cache']))
  709. {
  710. $this->event_clean_cache = $config['event_clean_cache'];
  711. }
  712. else
  713. {
  714. $this->event_clean_cache = $this->configProvider->get(
  715. $configKey . 'event_clean_cache',
  716. $this->event_clean_cache
  717. );
  718. }
  719. // Apply model behaviors
  720. if (isset($config['behaviors']))
  721. {
  722. $behaviors = (array) $config['behaviors'];
  723. }
  724. elseif ($behaviors = $this->configProvider->get($configKey . 'behaviors', null))
  725. {
  726. $behaviors = explode(',', $behaviors);
  727. }
  728. else
  729. {
  730. $behaviors = $this->default_behaviors;
  731. }
  732. if (is_array($behaviors) && count($behaviors))
  733. {
  734. foreach ($behaviors as $behavior)
  735. {
  736. $this->addBehavior($behavior);
  737. }
  738. }
  739. }
  740. /**
  741. * Sets the list of IDs from the request data
  742. *
  743. * @return FOFModel
  744. */
  745. public function setIDsFromRequest()
  746. {
  747. // Get the ID or list of IDs from the request or the configuration
  748. $cid = $this->input->get('cid', array(), 'array');
  749. $id = $this->input->getInt('id', 0);
  750. $kid = $this->input->getInt($this->getTable($this->table)->getKeyName(), 0);
  751. if (is_array($cid) && !empty($cid))
  752. {
  753. $this->setIds($cid);
  754. }
  755. else
  756. {
  757. if (empty($id))
  758. {
  759. $this->setId($kid);
  760. }
  761. else
  762. {
  763. $this->setId($id);
  764. }
  765. }
  766. return $this;
  767. }
  768. /**
  769. * Sets the ID and resets internal data
  770. *
  771. * @param integer $id The ID to use
  772. *
  773. * @throws InvalidArgumentException
  774. *
  775. * @return FOFModel
  776. */
  777. public function setId($id = 0)
  778. {
  779. // If this is an array extract the first item
  780. if (is_array($id))
  781. {
  782. FOFPlatform::getInstance()->logDeprecated('Passing arrays to FOFModel::setId is deprecated. Use setIds() instead.');
  783. $id = array_shift($id);
  784. }
  785. // No string or no integer? What are you trying to do???
  786. if (!is_string($id) && !is_numeric($id))
  787. {
  788. throw new InvalidArgumentException(sprintf('%s::setId()', get_class($this)));
  789. }
  790. $this->reset();
  791. $this->id = (int) $id;
  792. $this->id_list = array($this->id);
  793. return $this;
  794. }
  795. /**
  796. * Returns the currently set ID
  797. *
  798. * @return integer
  799. */
  800. public function getId()
  801. {
  802. return $this->id;
  803. }
  804. /**
  805. * Sets a list of IDs for batch operations from an array and resets the model
  806. *
  807. * @param array $idlist An array of item IDs to be set to the model's state
  808. *
  809. * @return FOFModel
  810. */
  811. public function setIds($idlist)
  812. {
  813. $this->reset();
  814. $this->id_list = array();
  815. $this->id = 0;
  816. if (is_array($idlist) && !empty($idlist))
  817. {
  818. foreach ($idlist as $value)
  819. {
  820. // Protect vs fatal error (objects) and wrong behavior (nested array)
  821. if(!is_object($value) && !is_array($value))
  822. {
  823. $this->id_list[] = (int) $value;
  824. }
  825. }
  826. if(count($this->id_list))
  827. {
  828. $this->id = $this->id_list[0];
  829. }
  830. }
  831. return $this;
  832. }
  833. /**
  834. * Returns the list of IDs for batch operations
  835. *
  836. * @return array An array of integers
  837. */
  838. public function getIds()
  839. {
  840. return $this->id_list;
  841. }
  842. /**
  843. * Resets the model, like it was freshly loaded
  844. *
  845. * @return FOFModel
  846. */
  847. public function reset()
  848. {
  849. $this->id = 0;
  850. $this->id_list = null;
  851. $this->record = null;
  852. $this->list = null;
  853. $this->pagination = null;
  854. $this->total = null;
  855. $this->otable = null;
  856. return $this;
  857. }
  858. /**
  859. * Clears the model state, but doesn't touch the internal lists of records,
  860. * record tables or record id variables. To clear these values, please use
  861. * reset().
  862. *
  863. * @return FOFModel
  864. */
  865. public function clearState()
  866. {
  867. $this->state = new FOFUtilsObject;
  868. return $this;
  869. }
  870. /**
  871. * Clears the input array.
  872. *
  873. * @return FOFModel
  874. */
  875. public function clearInput()
  876. {
  877. $defSource = array();
  878. $this->input = new FOFInput($defSource);
  879. return $this;
  880. }
  881. /**
  882. * Set the internal input field
  883. *
  884. * @param $input
  885. *
  886. * @return FOFModel
  887. */
  888. public function setInput($input)
  889. {
  890. if (!($input instanceof FOFInput))
  891. {
  892. if (!is_array($input))
  893. {
  894. $input = (array) $input;
  895. }
  896. $input = array_merge($_REQUEST, $input);
  897. $input = new FOFInput($input);
  898. }
  899. $this->input = $input;
  900. return $this;
  901. }
  902. /**
  903. * Resets the saved state for this view
  904. *
  905. * @return FOFModel
  906. */
  907. public function resetSavedState()
  908. {
  909. JFactory::getApplication()->setUserState(substr($this->getHash(), 0, -1), null);
  910. return $this;
  911. }
  912. /**
  913. * Returns a single item. It uses the id set with setId, or the first ID in
  914. * the list of IDs for batch operations
  915. *
  916. * @param integer $id Force a primary key ID to the model. Use null to use the id from the state.
  917. *
  918. * @return FOFTable A copy of the item's FOFTable array
  919. */
  920. public function &getItem($id = null)
  921. {
  922. if (!is_null($id))
  923. {
  924. $this->record = null;
  925. $this->setId($id);
  926. }
  927. if (empty($this->record))
  928. {
  929. $table = $this->getTable($this->table);
  930. $table->load($this->id);
  931. $this->record = $table;
  932. // Do we have saved data?
  933. $session = JFactory::getSession();
  934. if ($this->_savestate)
  935. {
  936. $serialized = $session->get($this->getHash() . 'savedata', null);
  937. if (!empty($serialized))
  938. {
  939. $data = @unserialize($serialized);
  940. if ($data !== false)
  941. {
  942. $k = $table->getKeyName();
  943. if (!array_key_exists($k, $data))
  944. {
  945. $data[$k] = null;
  946. }
  947. if ($data[$k] != $this->id)
  948. {
  949. $session->set($this->getHash() . 'savedata', null);
  950. }
  951. else
  952. {
  953. $this->record->bind($data);
  954. }
  955. }
  956. }
  957. }
  958. $this->onAfterGetItem($this->record);
  959. }
  960. return $this->record;
  961. }
  962. /**
  963. * Alias for getItemList
  964. *
  965. * @param boolean $overrideLimits Should I override set limits?
  966. * @param string $group The group by clause
  967. * @codeCoverageIgnore
  968. *
  969. * @return array
  970. */
  971. public function &getList($overrideLimits = false, $group = '')
  972. {
  973. return $this->getItemList($overrideLimits, $group);
  974. }
  975. /**
  976. * Returns a list of items
  977. *
  978. * @param boolean $overrideLimits Should I override set limits?
  979. * @param string $group The group by clause
  980. *
  981. * @return array
  982. */
  983. public function &getItemList($overrideLimits = false, $group = '')
  984. {
  985. if (empty($this->list))
  986. {
  987. $query = $this->buildQuery($overrideLimits);
  988. if (!$overrideLimits)
  989. {
  990. $limitstart = $this->getState('limitstart');
  991. $limit = $this->getState('limit');
  992. $this->list = $this->_getList((string) $query, $limitstart, $limit, $group);
  993. }
  994. else
  995. {
  996. $this->list = $this->_getList((string) $query, 0, 0, $group);
  997. }
  998. }
  999. return $this->list;
  1000. }
  1001. /**
  1002. * Returns a FOFDatabaseIterator over a list of items.
  1003. *
  1004. * THERE BE DRAGONS. Unlike the getItemList() you have a few restrictions:
  1005. * - The onProcessList event does not run when you get an iterator
  1006. * - The Iterator returns FOFTable instances. By default, $this->table is used. If you have JOINs, GROUPs or a
  1007. * complex query in general you will need to create a custom FOFTable subclass and pass its type in $tableType.
  1008. *
  1009. * The getIterator() method is a great way to sift through a large amount of records which would otherwise not fit
  1010. * in memory since it only keeps one record in PHP memory at a time. It works best with simple models, returning
  1011. * all the contents of a single database table.
  1012. *
  1013. * @param boolean $overrideLimits Should I ignore set limits?
  1014. * @param string $tableClass The table class for the iterator, e.g. FoobarTableBar. Leave empty to use
  1015. * the default Table class for this Model.
  1016. *
  1017. * @return FOFDatabaseIterator
  1018. */
  1019. public function &getIterator($overrideLimits = false, $tableClass = null)
  1020. {
  1021. // Get the table name (required by the Iterator)
  1022. if (empty($tableClass))
  1023. {
  1024. $name = $this->table;
  1025. if (empty($name))
  1026. {
  1027. $name = FOFInflector::singularize($this->getName());
  1028. }
  1029. $bareComponent = str_replace('com_', '', $this->option);
  1030. $prefix = ucfirst($bareComponent) . 'Table';
  1031. $tableClass = $prefix . ucfirst($name);
  1032. }
  1033. // Get the query
  1034. $query = $this->buildQuery($overrideLimits);
  1035. // Apply limits
  1036. if ($overrideLimits)
  1037. {
  1038. $limitStart = 0;
  1039. $limit = 0;
  1040. }
  1041. else
  1042. {
  1043. $limitStart = $this->getState('limitstart');
  1044. $limit = $this->getState('limit');
  1045. }
  1046. // This is required to prevent one relation from killing the db cursor used in a different relation...
  1047. $oldDb = $this->getDbo();
  1048. $oldDb->disconnect(); // YES, WE DO NEED TO DISCONNECT BEFORE WE CLONE THE DB OBJECT. ARGH!
  1049. $db = clone $oldDb;
  1050. // Execute the query, get a db cursor and return the iterator
  1051. $db->setQuery($query, $limitStart, $limit);
  1052. $cursor = $db->execute();
  1053. $iterator = FOFDatabaseIterator::getIterator($db->name, $cursor, null, $tableClass);
  1054. return $iterator;
  1055. }
  1056. /**
  1057. * A cross-breed between getItem and getItemList. It runs the complete query,
  1058. * like getItemList does. However, instead of returning an array of ad-hoc
  1059. * objects, it binds the data from the first item fetched on the list to an
  1060. * instance of the table object and returns that table object instead.
  1061. *
  1062. * @param boolean $overrideLimits Should I override set limits?
  1063. *
  1064. * @return FOFTable
  1065. */
  1066. public function &getFirstItem($overrideLimits = false)
  1067. {
  1068. /**
  1069. * We have to clone the instance, or when multiple getFirstItem calls occur,
  1070. * we'll update EVERY instance created
  1071. */
  1072. $table = clone $this->getTable($this->table);
  1073. $list = $this->getItemList($overrideLimits);
  1074. if (!empty($list))
  1075. {
  1076. $firstItem = array_shift($list);
  1077. $table->bind($firstItem);
  1078. }
  1079. unset($list);
  1080. return $table;
  1081. }
  1082. /**
  1083. * Binds the data to the model and tries to save it
  1084. *
  1085. * @param array|object $data The source data array or object
  1086. *
  1087. * @return boolean True on success
  1088. */
  1089. public function save($data)
  1090. {
  1091. $this->otable = null;
  1092. $table = $this->getTable($this->table);
  1093. if (is_object($data))
  1094. {
  1095. $data = clone($data);
  1096. }
  1097. $key = $table->getKeyName();
  1098. if (array_key_exists($key, (array) $data))
  1099. {
  1100. $aData = (array) $data;
  1101. $oid = $aData[$key];
  1102. $table->load($oid);
  1103. }
  1104. if ($data instanceof FOFTable)
  1105. {
  1106. $allData = $data->getData();
  1107. }
  1108. elseif (is_object($data))
  1109. {
  1110. $allData = (array) $data;
  1111. }
  1112. else
  1113. {
  1114. $allData = $data;
  1115. }
  1116. // Get the form if there is any
  1117. $form = $this->getForm($allData, false);
  1118. if ($form instanceof FOFForm)
  1119. {
  1120. // Make sure that $allData has for any field a key
  1121. $fieldset = $form->getFieldset();
  1122. foreach ($fieldset as $nfield => $fldset)
  1123. {
  1124. if (!array_key_exists($nfield, $allData))
  1125. {
  1126. $field = $form->getField($fldset->fieldname, $fldset->group);
  1127. $type = strtolower($field->type);
  1128. switch ($type)
  1129. {
  1130. case 'checkbox':
  1131. $allData[$nfield] = 0;
  1132. break;
  1133. default:
  1134. $allData[$nfield] = '';
  1135. break;
  1136. }
  1137. }
  1138. }
  1139. $serverside_validate = strtolower($form->getAttribute('serverside_validate'));
  1140. $validateResult = true;
  1141. if (in_array($serverside_validate, array('true', 'yes', '1', 'on')))
  1142. {
  1143. $validateResult = $this->validateForm($form, $allData);
  1144. }
  1145. if ($validateResult === false)
  1146. {
  1147. if ($this->_savestate)
  1148. {
  1149. $session = JFactory::getSession();
  1150. $hash = $this->getHash() . 'savedata';
  1151. $session->set($hash, serialize($allData));
  1152. }
  1153. return false;
  1154. }
  1155. }
  1156. if (!$this->onBeforeSave($allData, $table))
  1157. {
  1158. return false;
  1159. }
  1160. else
  1161. {
  1162. // If onBeforeSave successful, refetch the possibly modified data
  1163. if ($data instanceof FOFTable)
  1164. {
  1165. $data->bind($allData);
  1166. }
  1167. elseif (is_object($data))
  1168. {
  1169. $data = (object) $allData;
  1170. }
  1171. else
  1172. {
  1173. $data = $allData;
  1174. }
  1175. }
  1176. if (!$table->save($data))
  1177. {
  1178. foreach ($table->getErrors() as $error)
  1179. {
  1180. if (!empty($error))
  1181. {
  1182. $this->setError($error);
  1183. $session = JFactory::getSession();
  1184. $tableprops = $table->getProperties(true);
  1185. unset($tableprops['input']);
  1186. unset($tableprops['config']['input']);
  1187. unset($tableprops['config']['db']);
  1188. unset($tableprops['config']['dbo']);
  1189. if ($this->_savestate)
  1190. {
  1191. $hash = $this->getHash() . 'savedata';
  1192. $session->set($hash, serialize($tableprops));
  1193. }
  1194. }
  1195. }
  1196. return false;
  1197. }
  1198. else
  1199. {
  1200. $this->id = $table->$key;
  1201. // Remove the session data
  1202. if ($this->_savestate)
  1203. {
  1204. JFactory::getSession()->set($this->getHash() . 'savedata', null);
  1205. }
  1206. }
  1207. $this->onAfterSave($table);
  1208. $this->otable = $table;
  1209. return true;
  1210. }
  1211. /**
  1212. * Copy one or more records
  1213. *
  1214. * @return boolean True on success
  1215. */
  1216. public function copy()
  1217. {
  1218. if (is_array($this->id_list) && !empty($this->id_list))
  1219. {
  1220. $table = $this->getTable($this->table);
  1221. if (!$this->onBeforeCopy($table))
  1222. {
  1223. return false;
  1224. }
  1225. if (!$table->copy($this->id_list))
  1226. {
  1227. $this->setError($table->getError());
  1228. return false;
  1229. }
  1230. else
  1231. {
  1232. // Call our internal event
  1233. $this->onAfterCopy($table);
  1234. // @todo Should we fire the content plugin?
  1235. }
  1236. }
  1237. return true;
  1238. }
  1239. /**
  1240. * Returns the table object after the last save() operation
  1241. *
  1242. * @return FOFTable
  1243. */
  1244. public function getSavedTable()
  1245. {
  1246. return $this->otable;
  1247. }
  1248. /**
  1249. * Deletes one or several items
  1250. *
  1251. * @return boolean True on success
  1252. */
  1253. public function delete()
  1254. {
  1255. if (is_array($this->id_list) && !empty($this->id_list))
  1256. {
  1257. $table = $this->getTable($this->table);
  1258. foreach ($this->id_list as $id)
  1259. {
  1260. if (!$this->onBeforeDelete($id, $table))
  1261. {
  1262. continue;
  1263. }
  1264. if (!$table->delete($id))
  1265. {
  1266. $this->setError($table->getError());
  1267. return false;
  1268. }
  1269. else
  1270. {
  1271. $this->onAfterDelete($id);
  1272. }
  1273. }
  1274. }
  1275. return true;
  1276. }
  1277. /**
  1278. * Toggles the published state of one or several items
  1279. *
  1280. * @param integer $publish The publishing state to set (e.g. 0 is unpublished)
  1281. * @param integer $user The user ID performing this action
  1282. *
  1283. * @return boolean True on success
  1284. */
  1285. public function publish($publish = 1, $user = null)
  1286. {
  1287. if (is_array($this->id_list) && !empty($this->id_list))
  1288. {
  1289. if (empty($user))
  1290. {
  1291. $oUser = FOFPlatform::getInstance()->getUser();
  1292. $user = $oUser->id;
  1293. }
  1294. $table = $this->getTable($this->table);
  1295. if (!$this->onBeforePublish($table))
  1296. {
  1297. return false;
  1298. }
  1299. if (!$table->publish($this->id_list, $publish, $user))
  1300. {
  1301. $this->setError($table->getError());
  1302. return false;
  1303. }
  1304. else
  1305. {
  1306. // Call our internal event
  1307. $this->onAfterPublish($table);
  1308. // Call the plugin events
  1309. FOFPlatform::getInstance()->importPlugin('content');
  1310. $name = $this->name;
  1311. $context = $this->option . '.' . $name;
  1312. // @TODO should we do anything with this return value?
  1313. $result = FOFPlatform::getInstance()->runPlugins($this->event_change_state, array($context, $this->id_list, $publish));
  1314. }
  1315. }
  1316. return true;
  1317. }
  1318. /**
  1319. * Checks out the current item
  1320. *
  1321. * @return boolean
  1322. */
  1323. public function checkout()
  1324. {
  1325. $table = $this->getTable($this->table);
  1326. $status = $table->checkout(FOFPlatform::getInstance()->getUser()->id, $this->id);
  1327. if (!$status)
  1328. {
  1329. $this->setError($table->getError());
  1330. }
  1331. return $status;
  1332. }
  1333. /**
  1334. * Checks in the current item
  1335. *
  1336. * @return boolean
  1337. */
  1338. public function checkin()
  1339. {
  1340. $table = $this->getTable($this->table);
  1341. $status = $table->checkin($this->id);
  1342. if (!$status)
  1343. {
  1344. $this->setError($table->getError());
  1345. }
  1346. return $status;
  1347. }
  1348. /**
  1349. * Tells you if the current item is checked out or not
  1350. *
  1351. * @return boolean
  1352. */
  1353. public function isCheckedOut()
  1354. {
  1355. $table = $this->getTable($this->table);
  1356. $status = $table->isCheckedOut($this->id);
  1357. if (!$status)
  1358. {
  1359. $this->setError($table->getError());
  1360. }
  1361. return $status;
  1362. }
  1363. /**
  1364. * Increments the hit counter
  1365. *
  1366. * @return boolean
  1367. */
  1368. public function hit()
  1369. {
  1370. $table = $this->getTable($this->table);
  1371. if (!$this->onBeforeHit($table))
  1372. {
  1373. return false;
  1374. }
  1375. $status = $table->hit($this->id);
  1376. if (!$status)
  1377. {
  1378. $this->setError($table->getError());
  1379. }
  1380. else
  1381. {
  1382. $this->onAfterHit($table);
  1383. }
  1384. return $status;
  1385. }
  1386. /**
  1387. * Moves the current item up or down in the ordering list
  1388. *
  1389. * @param string $dirn The direction and magnitude to use (2 means move up by 2 positions, -3 means move down three positions)
  1390. *
  1391. * @return boolean True on success
  1392. */
  1393. public function move($dirn)
  1394. {
  1395. $table = $this->getTable($this->table);
  1396. $id = $this->getId();
  1397. $status = $table->load($id);
  1398. if (!$status)
  1399. {
  1400. $this->setError($table->getError());
  1401. }
  1402. if (!$status)
  1403. {
  1404. return false;
  1405. }
  1406. if (!$this->onBeforeMove($table))
  1407. {
  1408. return false;
  1409. }
  1410. $status = $table->move($dirn);
  1411. if (!$status)
  1412. {
  1413. $this->setError($table->getError());
  1414. }
  1415. else
  1416. {
  1417. $this->onAfterMove($table);
  1418. }
  1419. return $status;
  1420. }
  1421. /**
  1422. * Reorders all items in the table
  1423. *
  1424. * @return boolean
  1425. */
  1426. public function reorder()
  1427. {
  1428. $table = $this->getTable($this->table);
  1429. if (!$this->onBeforeReorder($table))
  1430. {
  1431. return false;
  1432. }
  1433. $status = $table->reorder($this->getReorderWhere());
  1434. if (!$status)
  1435. {
  1436. $this->setError($table->getError());
  1437. }
  1438. else
  1439. {
  1440. if (!$this->onAfterReorder($table))
  1441. {
  1442. return false;
  1443. }
  1444. }
  1445. return $status;
  1446. }
  1447. /**
  1448. * Get a pagination object
  1449. *
  1450. * @return JPagination
  1451. */
  1452. public function getPagination()
  1453. {
  1454. if (empty($this->pagination))
  1455. {
  1456. // Import the pagination library
  1457. JLoader::import('joomla.html.pagination');
  1458. // Prepare pagination values
  1459. $total = $this->getTotal();
  1460. $limitstart = $this->getState('limitstart');
  1461. $limit = $this->getState('limit');
  1462. // Create the pagination object
  1463. $this->pagination = new JPagination($total, $limitstart, $limit);
  1464. }
  1465. return $this->pagination;
  1466. }
  1467. /**
  1468. * Get the number of all items
  1469. *
  1470. * @return integer
  1471. */
  1472. public function getTotal()
  1473. {
  1474. if (is_null($this->total))
  1475. {
  1476. $query = $this->buildCountQuery();
  1477. if ($query === false)
  1478. {
  1479. $subquery = $this->buildQuery(false);
  1480. $subquery->clear('order');
  1481. $query = $this->_db->getQuery(true)
  1482. ->select('COUNT(*)')
  1483. ->from("(" . (string) $subquery . ") AS a");
  1484. }
  1485. $this->_db->setQuery((string) $query);
  1486. $this->total = $this->_db->loadResult();
  1487. }
  1488. return $this->total;
  1489. }
  1490. /**
  1491. * Returns a record count for the query
  1492. *
  1493. * @param string $query The query.
  1494. *
  1495. * @return integer Number of rows for query
  1496. *
  1497. * @since 12.2
  1498. */
  1499. protected function _getListCount($query)
  1500. {
  1501. return $this->getTotal();
  1502. }
  1503. /**
  1504. * Get a filtered state variable
  1505. *
  1506. * @param string $key The name of the state variable
  1507. * @param mixed $default The default value to use
  1508. * @param string $filter_type Filter type
  1509. *
  1510. * @return mixed The variable's value
  1511. */
  1512. public function getState($key = null, $default = null, $filter_type = 'raw')
  1513. {
  1514. if (empty($key))
  1515. {
  1516. return $this->_real_getState();
  1517. }
  1518. // Get the savestate status
  1519. $value = $this->_real_getState($key);
  1520. if (is_null($value))
  1521. {
  1522. $value = $this->getUserStateFromRequest($this->getHash() . $key, $key, $value, 'none', $this->_savestate);
  1523. if (is_null($value))
  1524. {
  1525. return $default;
  1526. }
  1527. }
  1528. if (strtoupper($filter_type) == 'RAW')
  1529. {
  1530. return $value;
  1531. }
  1532. else
  1533. {
  1534. JLoader::import('joomla.filter.filterinput');
  1535. $filter = new JFilterInput;
  1536. return $filter->clean($value, $filter_type);
  1537. }
  1538. }
  1539. /**
  1540. * Method to get model state variables
  1541. *
  1542. * @param string $property Optional parameter name
  1543. * @param mixed $default Optional default value
  1544. *
  1545. * @return object The property where specified, the state object where omitted
  1546. *
  1547. * @since 12.2
  1548. */
  1549. protected function _real_getState($property = null, $default = null)
  1550. {
  1551. if (!$this->__state_set)
  1552. {
  1553. // Protected method to auto-populate the model state.
  1554. $this->populateState();
  1555. // Set the model state set flag to true.
  1556. $this->__state_set = true;
  1557. }
  1558. return $property === null ? $this->state : $this->state->get($property, $default);
  1559. }
  1560. /**
  1561. * Returns a hash for this component and view, e.g. "foobar.items.", used
  1562. * for determining the keys of the variables which will be placed in the
  1563. * session storage.
  1564. *
  1565. * @return string The hash
  1566. */
  1567. public function getHash()
  1568. {
  1569. $option = $this->input->getCmd('option', 'com_foobar');
  1570. $view = FOFInflector::pluralize($this->input->getCmd('view', 'cpanel'));
  1571. return "$option.$view.";
  1572. }
  1573. /**
  1574. * Gets the value of a user state variable.
  1575. *
  1576. * @param string $key The key of the user state variable.
  1577. * @param string $request The name of the variable passed in a request.
  1578. * @param string $default The default value for the variable if not found. Optional.
  1579. * @param string $type Filter for the variable, for valid values see {@link JFilterInput::clean()}. Optional.
  1580. * @param boolean $setUserState Should I save the variable in the user state? Default: true. Optional.
  1581. *
  1582. * @return string The request user state.
  1583. */
  1584. protected function getUserStateFromRequest($key, $request, $default = null, $type = 'none', $setUserState = true)
  1585. {
  1586. return FOFPlatform::getInstance()->getUserStateFromRequest($key, $request, $this->input, $default, $type, $setUserState);
  1587. }
  1588. /**
  1589. * Returns an object list
  1590. *
  1591. * @param string $query The query
  1592. * @param integer $limitstart Offset from start
  1593. * @param integer $limit The number of records
  1594. * @param string $group The group by clause
  1595. *
  1596. * @return array Array of objects
  1597. */
  1598. protected function &_getList($query, $limitstart = 0, $limit = 0, $group = '')
  1599. {
  1600. $this->_db->setQuery($query, $limitstart, $limit);
  1601. $result = $this->_db->loadObjectList($group);
  1602. $this->onProcessList($result);
  1603. return $result;
  1604. }
  1605. /**
  1606. * Method to get a table object, load it if necessary.
  1607. *
  1608. * @param string $name The table name. Optional.
  1609. * @param string $prefix The class prefix. Optional.
  1610. * @param array $options Configuration array for model. Optional.
  1611. *
  1612. * @throws Exception
  1613. *
  1614. * @return FOFTable A FOFTable object
  1615. */
  1616. public function getTable($name = '', $prefix = null, $options = array())
  1617. {
  1618. if (empty($name))
  1619. {
  1620. $name = $this->table;
  1621. if (empty($name))
  1622. {
  1623. $name = FOFInflector::singularize($this->getName());
  1624. }
  1625. }
  1626. if (empty($prefix))
  1627. {
  1628. $bareComponent = str_replace('com_', '', $this->option);
  1629. $prefix = ucfirst($bareComponent) . 'Table';
  1630. }
  1631. if (empty($options))
  1632. {
  1633. $options = array('input' => $this->input);
  1634. }
  1635. if ($table = $this->_createTable($name, $prefix, $options))
  1636. {
  1637. return $table;
  1638. }
  1639. FOFPlatform::getInstance()->raiseError(0, JText::sprintf('JLIB_APPLICATION_ERROR_TABLE_NAME_NOT_SUPPORTED', $name));
  1640. return null;
  1641. }
  1642. /**
  1643. * Method to load and return a model object.
  1644. *
  1645. * @param string $name The name of the view
  1646. * @param string $prefix The class prefix. Optional.
  1647. * @param array $config The configuration array to pass to the table
  1648. *
  1649. * @return FOFTable Table object or boolean false if failed
  1650. */
  1651. protected function &_createTable($name, $prefix = 'Table', $config = array())
  1652. {
  1653. // Make sure $config is an array
  1654. if (is_object($config))
  1655. {
  1656. $config = (array) $config;
  1657. }
  1658. elseif (!is_array($config))
  1659. {
  1660. $config = array();
  1661. }
  1662. $result = null;
  1663. // Clean the model name
  1664. $name = preg_replace('/[^A-Z0-9_]/i', '', $name);
  1665. $prefix = preg_replace('/[^A-Z0-9_]/i', '', $prefix);
  1666. // Make sure we are returning a DBO object
  1667. if (!array_key_exists('dbo', $config))
  1668. {
  1669. $config['dbo'] = $this->getDBO();
  1670. }
  1671. $instance = FOFTable::getAnInstance($name, $prefix, $config);
  1672. return $instance;
  1673. }
  1674. /**
  1675. * Creates the WHERE part of the reorder query
  1676. *
  1677. * @return string
  1678. */
  1679. public function getReorderWhere()
  1680. {
  1681. return '';
  1682. }
  1683. /**
  1684. * Builds the SELECT query
  1685. *
  1686. * @param boolean $overrideLimits Are we requested to override the set limits?
  1687. *
  1688. * @return JDatabaseQuery
  1689. */
  1690. public function buildQuery($overrideLimits = false)
  1691. {
  1692. $table = $this->getTable();
  1693. $tableName = $table->getTableName();
  1694. $tableKey = $table->getKeyName();
  1695. $db = $this->getDbo();
  1696. $query = $db->getQuery(true);
  1697. // Call the behaviors
  1698. $this->modelDispatcher->trigger('onBeforeBuildQuery', array(&$this, &$query));
  1699. $alias = $this->getTableAlias();
  1700. if ($alias)
  1701. {
  1702. $alias = ' AS ' . $db->qn($alias);
  1703. }
  1704. else
  1705. {
  1706. $alias = '';
  1707. }
  1708. $select = $this->getTableAlias() ? $db->qn($this->getTableAlias()) . '.*' : $db->qn($tableName) . '.*';
  1709. $query->select($select)->from($db->qn($tableName) . $alias);
  1710. if (!$overrideLimits)
  1711. {
  1712. $order = $this->getState('filter_order', null, 'cmd');
  1713. if (!in_array($order, array_keys($table->getData())))
  1714. {
  1715. $order = $tableKey;
  1716. }
  1717. $order = $db->qn($order);
  1718. if ($alias)
  1719. {
  1720. $order = $db->qn($this->getTableAlias()) . '.' . $order;
  1721. }
  1722. $dir = $this->getState('filter_order_Dir', 'ASC', 'cmd');
  1723. $query->order($order . ' ' . $dir);
  1724. }
  1725. // Call the behaviors
  1726. $this->modelDispatcher->trigger('onAfterBuildQuery', array(&$this, &$query));
  1727. return $query;
  1728. }
  1729. /**
  1730. * Returns a list of the fields of the table associated with this model
  1731. *
  1732. * @return array
  1733. */
  1734. public function getTableFields()
  1735. {
  1736. $tableName = $this->getTable()->getTableName();
  1737. if (version_compare(JVERSION, '3.0', 'ge'))
  1738. {
  1739. $fields = $this->getDbo()->getTableColumns($tableName, true);
  1740. }
  1741. else
  1742. {
  1743. $fieldsArray = $this->getDbo()->getTableFields($tableName, true);
  1744. $fields = array_shift($fieldsArray);
  1745. }
  1746. return $fields;
  1747. }
  1748. /**
  1749. * Get the alias set for this model's table
  1750. *
  1751. * @return string The table alias
  1752. */
  1753. public function getTableAlias()
  1754. {
  1755. return $this->getTable($this->table)->getTableAlias();
  1756. }
  1757. /**
  1758. * Builds the count query used in getTotal()
  1759. *
  1760. * @return boolean
  1761. */
  1762. public function buildCountQuery()
  1763. {
  1764. return false;
  1765. }
  1766. /**
  1767. * Clones the model object and returns the clone
  1768. *
  1769. * @return FOFModel
  1770. */
  1771. public function &getClone()
  1772. {
  1773. $clone = clone($this);
  1774. return $clone;
  1775. }
  1776. /**
  1777. * Magic getter; allows to use the name of model state keys as properties
  1778. *
  1779. * @param string $name The name of the variable to get
  1780. *
  1781. * @return mixed The value of the variable
  1782. */
  1783. public function __get($name)
  1784. {
  1785. return $this->getState($name);
  1786. }
  1787. /**
  1788. * Magic setter; allows to use the name of model state keys as properties
  1789. *
  1790. * @param string $name The name of the variable
  1791. * @param mixed $value The value to set the variable to
  1792. *
  1793. * @return void
  1794. */
  1795. public function __set($name, $value)
  1796. {
  1797. return $this->setState($name, $value);
  1798. }
  1799. /**
  1800. * Magic caller; allows to use the name of model state keys as methods to
  1801. * set their values.
  1802. *
  1803. * @param string $name The name of the state variable to set
  1804. * @param mixed $arguments The value to set the state variable to
  1805. *
  1806. * @return FOFModel Reference to self
  1807. */
  1808. public function __call($name, $arguments)
  1809. {
  1810. $arg1 = array_shift($arguments);
  1811. $this->setState($name, $arg1);
  1812. return $this;
  1813. }
  1814. /**
  1815. * Sets the model state auto-save status. By default the model is set up to
  1816. * save its state to the session.
  1817. *
  1818. * @param boolean $newState True to save the state, false to not save it.
  1819. *
  1820. * @return FOFModel Reference to self
  1821. */
  1822. public function &savestate($newState)
  1823. {
  1824. $this->_savestate = $newState ? true : false;
  1825. return $this;
  1826. }
  1827. /**
  1828. * Initialises the _savestate variable
  1829. *
  1830. * @param integer $defaultSaveState The default value for the savestate
  1831. *
  1832. * @return void
  1833. */
  1834. public function populateSavestate($defaultSaveState = -999)
  1835. {
  1836. if (is_null($this->_savestate))
  1837. {
  1838. $savestate = $this->input->getInt('savestate', $defaultSaveState);
  1839. if ($savestate == -999)
  1840. {
  1841. $savestate = true;
  1842. }
  1843. $this->savestate($savestate);
  1844. }
  1845. }
  1846. /**
  1847. * Method to auto-populate the model state.
  1848. *
  1849. * This method should only be called once per instantiation and is designed
  1850. * to be called on the first call to the getState() method unless the model
  1851. * configuration flag to ignore the request is set.
  1852. *
  1853. * @return void
  1854. *
  1855. * @note Calling getState in this method will result in recursion.
  1856. * @since 12.2
  1857. */
  1858. protected function populateState()
  1859. {
  1860. }
  1861. /**
  1862. * Applies view access level filtering for the specified user. Useful to
  1863. * filter a front-end items listing.
  1864. *
  1865. * @param integer $userID The user ID to use. Skip it to use the currently logged in user.
  1866. *
  1867. * @return FOFModel Reference to self
  1868. */
  1869. public function applyAccessFiltering($userID = null)
  1870. {
  1871. $user = FOFPlatform::getInstance()->getUser($userID);
  1872. $table = $this->getTable();
  1873. $accessField = $table->getColumnAlias('access');
  1874. $this->setState($accessField, $user->getAuthorisedViewLevels());
  1875. return $this;
  1876. }
  1877. /**
  1878. * A method for getting the form from the model.
  1879. *
  1880. * @param array $data Data for the form.
  1881. * @param boolean $loadData True if the form is to load its own data (default case), false if not.
  1882. * @param boolean $source The name of the form. If not set we'll try the form_name state variable or fall back to default.
  1883. *
  1884. * @return mixed A FOFForm object on success, false on failure
  1885. *
  1886. * @since 2.0
  1887. */
  1888. public function getForm($data = array(), $loadData = true, $source = null)
  1889. {
  1890. $this->_formData = $data;
  1891. $name = $this->input->getCmd('option', 'com_foobar') . '.' . $this->name;
  1892. if (empty($source))
  1893. {
  1894. $source = $this->getState('form_name', null);
  1895. }
  1896. if (empty($source))
  1897. {
  1898. $source = 'form.' . $this->name;
  1899. }
  1900. $options = array(
  1901. 'control' => false,
  1902. 'load_data' => $loadData,
  1903. );
  1904. $this->onBeforeLoadForm($name, $source, $options);
  1905. $form = $this->loadForm($name, $source, $options);
  1906. if ($form instanceof FOFForm)
  1907. {
  1908. $this->onAfterLoadForm($form, $name, $source, $options);
  1909. }
  1910. return $form;
  1911. }
  1912. /**
  1913. * Method to get a form object.
  1914. *
  1915. * @param string $name The name of the form.
  1916. * @param string $source The form filename (e.g. form.browse)
  1917. * @param array $options Optional array of options for the form creation.
  1918. * @param boolean $clear Optional argument to force load a new form.
  1919. * @param bool|string $xpath An optional xpath to search for the fields.
  1920. *
  1921. * @return mixed FOFForm object on success, False on error.
  1922. *
  1923. * @see FOFForm
  1924. * @since 2.0
  1925. */
  1926. protected function loadForm($name, $source, $options = array(), $clear = false, $xpath = false)
  1927. {
  1928. // Handle the optional arguments.
  1929. $options['control'] = isset($options['control']) ? $options['control'] : false;
  1930. // Create a signature hash.
  1931. $hash = md5($source . serialize($options));
  1932. // Check if we can use a previously loaded form.
  1933. if (isset($this->_forms[$hash]) && !$clear)
  1934. {
  1935. return $this->_forms[$hash];
  1936. }
  1937. // Try to find the name and path of the form to load
  1938. $formFilename = $this->findFormFilename($source);
  1939. // No form found? Quit!
  1940. if ($formFilename === false)
  1941. {
  1942. return false;
  1943. }
  1944. // Set up the form name and path
  1945. $source = basename($formFilename, '.xml');
  1946. FOFForm::addFormPath(dirname($formFilename));
  1947. // Set up field paths
  1948. $option = $this->input->getCmd('option', 'com_foobar');
  1949. $componentPaths = FOFPlatform::getInstance()->getComponentBaseDirs($option);
  1950. $view = $this->name;
  1951. $file_root = $componentPaths['main'];
  1952. $alt_file_root = $componentPat

Large files files are truncated, but you can click here to view the full file