%PDF- %PDF-
Direktori : /home/lightco1/upgrade.lightco.com.au/libraries/fof30/Model/ |
Current File : /home/lightco1/upgrade.lightco.com.au/libraries/fof30/Model/Model.php |
<?php /** * @package FOF * @copyright 2010-2017 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU GPL version 2 or later */ namespace FOF30\Model; use FOF30\Container\Container; use FOF30\Input\Input; use FOF30\Model\Exception\CannotGetName; use FOF30\Utils\StringHelper; defined('_JEXEC') or die; /** * Class Model * * A generic MVC model implementation * * @property-read \FOF30\Input\Input $input The input object (magic __get returns the Input from the Container) */ class Model { /** * Should I save the model's state in the session? * * @var boolean */ protected $_savestate = true; /** * Should we ignore request data when trying to get state data not already set in the Model? * * @var bool */ protected $_ignoreRequest = false; /** * The model (base) name * * @var string */ protected $name; /** * A state object * * @var string */ protected $state; /** * Are the state variables already set? * * @var boolean */ protected $_state_set = false; /** * The container attached to the model * * @var Container */ protected $container; /** * The state key hash returned by getHash(). This is typically something like "com_foobar.example." (note the dot * at the end). Always use getHash to get it and setHash to set it. * * @var null|string */ private $stateHash = null; /** * Public class constructor * * You can use the $config array to pass some configuration values to the object: * * state stdClass|array. The state variables of the Model. * use_populate Boolean. When true the model will set its state from populateState() instead of the request. * ignore_request Boolean. When true getState will not automatically load state data from the request. * * @param Container $container The configuration variables to this model * @param array $config Configuration values for this model */ public function __construct(Container $container, array $config = array()) { $this->container = $container; // Set the model's name from $config if (isset($config['name'])) { $this->name = $config['name']; } // If $config['name'] is not set, auto-detect the model's name $this->name = $this->getName(); // Do we have a configured state hash? Since 3.1.2. if (isset($config['hash']) && !empty($config['hash'])) { $this->setHash($config['hash']); } elseif (isset($config['hash_view']) && !empty($config['hash_view'])) { $this->getHash($config['hash_view']); } // Set the model state if (array_key_exists('state', $config)) { if (is_object($config['state'])) { $this->state = $config['state']; } elseif (is_array($config['state'])) { $this->state = (object)$config['state']; } // Protect vs malformed state else { $this->state = new \stdClass(); } } else { $this->state = new \stdClass(); } // Set the internal state marker if (!empty($config['use_populate'])) { $this->_state_set = true; } // Set the internal state marker if (!empty($config['ignore_request'])) { $this->_ignoreRequest = true; } } /** * Method to get the model name * * The model name. By default parsed using the classname or it can be set * by passing a $config['name'] in the class constructor * * @return string The name of the model * * @throws \RuntimeException If it's impossible to get the name */ public function getName() { if (empty($this->name)) { $r = null; if (!preg_match('/(.*)\\\\Model\\\\(.*)/i', get_class($this), $r)) { throw new CannotGetName; } $this->name = $r[2]; } return $this->name; } /** * Get a filtered state variable * * @param string $key The state variable's name * @param mixed $default The default value to return if it's not already set * @param string $filter_type The filter type to use * * @return mixed The state variable's contents */ public function getState($key = null, $default = null, $filter_type = 'raw') { if (empty($key)) { return $this->internal_getState(); } // Get the savestate status $value = $this->internal_getState($key); // Value is not found in the internal state if (is_null($value)) { // Can I fetch it from the request? if (!$this->_ignoreRequest) { $value = $this->container->platform->getUserStateFromRequest($this->getHash() . $key, $key, $this->input, $value, 'none', $this->_savestate); // Did I get any useful value from the request? if (is_null($value)) { return $default; } } // Nope! Let's return the default value else { return $default; } } if (strtoupper($filter_type) == 'RAW') { return $value; } else { $filter = new \JFilterInput(); return $filter->clean($value, $filter_type); } } /** * Returns a unique hash for each view, used to prefix the state variables to allow us to retrieve them from the * state later on. If it's not already set (with setHash) it will be set in the form com_something.myModel. If you * pass a non-empty $viewName then if it's not already set it will be instead set in the form of * com_something.viewName.myModel which is useful when you are reusing models in multiple views and want to avoid * state bleedover among views. * * Also see the hash and hash_view parameters in the constructor's options. * * @return string */ public function getHash($viewName = null) { if (is_null($this->stateHash)) { $this->stateHash = ucfirst($this->container->componentName) . '.'; if (!empty($viewName)) { $this->stateHash .= $viewName . '.'; } $this->stateHash .= $this->getName() . '.'; } return $this->stateHash; } /** * Sets the unique hash to prefix the state variables. The hash is cleaned according to the 'CMD' input filtering, * must end in a dot (if not a dot is added automatically) and cannot be empty. * * @param string $hash * * @return void * * @see self::getHash() */ public function setHash($hash) { // Clean the hash, it has to conform to 'CMD' filtering $tempInput = new Input(array('hash' => $hash)); $hash = $tempInput->getCmd('hash', null); if (empty($hash)) { return; } if (substr($hash, -1) == '_') { $hash = substr($hash, 0, -1); } if (substr($hash, -1) != '.') { $hash .= '.'; } $this->stateHash = $hash; } /** * Method to get model state variables * * @param string $property Optional parameter name * @param mixed $default Optional default value * * @return object The property where specified, the state object where omitted */ private function internal_getState($property = null, $default = null) { if (!$this->_state_set) { // Protected method to auto-populate the model state. $this->populateState(); // Set the model state set flag to true. $this->_state_set = true; } if (is_null($property)) { return $this->state; } else { if (property_exists($this->state, $property)) { return $this->state->$property; } else { return $default; } } } /** * Method to auto-populate the model state. * * This method should only be called once per instantiation and is designed * to be called on the first call to the getState() method unless the model * configuration flag to ignore the request is set. * * @return void * * @note Calling getState in this method will result in recursion. */ protected function populateState() { } /** * Method to set model state variables * * @param string $property The name of the property. * @param mixed $value The value of the property to set or null. * * @return mixed The previous value of the property or null if not set. */ public function setState($property, $value = null) { if (is_null($this->state)) { $this->state = new \stdClass(); } return $this->state->$property = $value; } /** * Clears the model state, but doesn't touch the internal lists of records, * record tables or record id variables. To clear these values, please use * reset(). * * @return static */ public function clearState() { $this->state = new \stdClass(); return $this; } /** * Clones the model object and returns the clone * * @return $this for chaining */ public function getClone() { $clone = clone($this); return $clone; } /** * Returns a reference to the model's container * * @return \FOF30\Container\Container */ public function getContainer() { return $this->container; } /** * Magic getter; allows to use the name of model state keys as properties. Also handles magic properties: * $this->input mapped to $this->container->input * * @param string $name The state variable key * * @return static */ public function __get($name) { // Handle $this->input if ($name == 'input') { return $this->container->input; } return $this->getState($name); } /** * Magic setter; allows to use the name of model state keys as properties * * @param string $name The state variable key * @param mixed $value The state variable value * * @return static */ public function __set($name, $value) { return $this->setState($name, $value); } /** * Magic caller; allows to use the name of model state keys as methods to * set their values. * * @param string $name The state variable key * @param mixed $arguments The state variable contents * * @return static */ public function __call($name, $arguments) { $arg1 = array_shift($arguments); $this->setState($name, $arg1); return $this; } /** * Sets the model state auto-save status. By default the model is set up to * save its state to the session. * * @param boolean $newState True to save the state, false to not save it. * * @return static */ public function savestate($newState) { $this->_savestate = $newState ? true : false; return $this; } /** * Public setter for the _savestate variable. Set it to true to save the state * of the Model in the session. * * @return static */ public function populateSavestate() { if (is_null($this->_savestate)) { $savestate = $this->input->getInt('savestate', -999); if ($savestate == -999) { $savestate = true; } $this->savestate($savestate); } } /** * Sets the ignore request flag. When false, getState() will try to populate state variables not already set from * same-named state variables in the request. * * @param boolean $ignoreRequest * * @return $this for chaining */ public function setIgnoreRequest($ignoreRequest) { $this->_ignoreRequest = $ignoreRequest; return $this; } /** * Gets the ignore request flag. When false, getState() will try to populate state variables not already set from * same-named state variables in the request. * * @return boolean */ public function getIgnoreRequest() { return $this->_ignoreRequest; } /** * Returns a temporary instance of the model. Please note that this returns a _clone_ of the model object, not the * original object. The new object is set up to not save its stats, ignore the request when getting state variables * and comes with an empty state. * * @return $this */ public function tmpInstance() { return $this->getClone()->savestate(false)->setIgnoreRequest(true)->clearState(); } /** * Triggers an object-specific event. The event runs both locally –if a suitable method exists– and through the * object's behaviours dispatcher and Joomla! plugin system. Neither handler is expected to return anything (return * values are ignored). If you want to mark an error and cancel the event you have to raise an exception. * * EXAMPLE * Component: com_foobar, Object name: item, Event: onBeforeSomething, Arguments: array(123, 456) * The event calls: * 1. $this->onBeforeSomething(123, 456) * 2. $his->behavioursDispatcher->trigger('onBeforeSomething', array(&$this, 123, 456)) * 3. Joomla! plugin event onComFoobarModelItemBeforeSomething($this, 123, 456) * * @param string $event The name of the event, typically named onPredicateVerb e.g. onBeforeKick * @param array $arguments The arguments to pass to the event handlers * * @return void */ protected function triggerEvent($event, array $arguments = array()) { // If there is an object method for this event, call it if (method_exists($this, $event)) { switch (count($arguments)) { case 0: $this->{$event}(); break; case 1: $this->{$event}($arguments[0]); break; case 2: $this->{$event}($arguments[0], $arguments[1]); break; case 3: $this->{$event}($arguments[0], $arguments[1], $arguments[2]); break; case 4: $this->{$event}($arguments[0], $arguments[1], $arguments[2], $arguments[3]); break; case 5: $this->{$event}($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]); break; default: call_user_func_array(array($this, $event), $arguments); break; } } // All other event handlers live outside this object, therefore they need to be passed a reference to this // objects as the first argument. array_unshift($arguments, $this); // Trigger the object's behaviours dispatcher, if such a thing exists if (property_exists($this, 'behavioursDispatcher') && method_exists($this->behavioursDispatcher, 'trigger')) { $this->behavioursDispatcher->trigger($event, $arguments); } // Prepare to run the Joomla! plugins now. // If we have an "on" prefix for the event (e.g. onFooBar) remove it and stash it for later. $prefix = ''; if (substr($event, 0, 2) == 'on') { $prefix = 'on'; $event = substr($event, 2); } // Get the component/model prefix for the event $prefix .= 'Com' . ucfirst($this->container->bareComponentName) . 'Model'; $prefix .= ucfirst($this->getName()); // The event name will be something like onComFoobarItemsBeforeSomething $event = $prefix . $event; // Call the Joomla! plugins $this->container->platform->runPlugins($event, $arguments); } }