/** * Returns the alternate view template paths (a.k.a. template overrides in Joomla!-speak) for the given View name * * @param string $viewName The name of the view triggering this event * * @return array The template override paths */ public function onGetViewTemplatePaths($viewName) { $container = $this->subject->getContainer(); $application_name = $container->application_name; $component_name = 'com_' . strtolower($application_name); // That's the path in the site's current template containing template overrides $overridePath = Helper::getTemplateOverridePath($component_name, true); // The alternative view name (pluralised if the view is singular, singularised if the view is plural) $altViewName = Inflector::isPlural($viewName) ? Inflector::singularize($viewName) : Inflector::pluralize($viewName); // Remember, each path is pushed to the TOP of the path stack. This means that the least important directory // must go FIRST so that it ends add being added LAST. return array($overridePath . '/' . $altViewName, $overridePath . '/' . $viewName); }
/** * Returns a new model object. Unless overridden by the $config array, it will * try to automatically populate its state from the request variables. * * By default the new model instance is created with persistent state, unless * you pass $config['modelTemporaryInstance'] = false * * @param string $appName The application name * @param string $modelName The model name * @param Container $container Configuration variables to the model * * @return static * * @throws \RuntimeException If the Model is not found */ public static function getInstance($appName = null, $modelName = '', $container = null) { if (empty($appName) && !is_object($container)) { $app = Application::getInstance(); $appName = $app->getName(); $container = $app->getContainer(); } elseif (empty($appName) && is_object($container)) { $appName = $container->application_name; } elseif (!empty($appName) && !is_object($container)) { $container = Application::getInstance($appName)->getContainer(); } $config = isset($container['mvc_config']) ? $container['mvc_config'] : array(); if (empty($modelName)) { $modelName = $container->input->getCmd('view', ''); } // Try to load the Model class $classes = array('\\' . ucfirst($appName) . '\\Model\\' . ucfirst($modelName), '\\' . ucfirst($appName) . '\\Model\\' . ucfirst(Inflector::pluralize($modelName)), '\\' . ucfirst($appName) . '\\Model\\DefaultModel'); foreach ($classes as $className) { if (class_exists($className)) { break; } } if (!class_exists($className)) { throw new \RuntimeException("Model not found (app : model) = {$appName} : {$modelName}"); } /** @var Model $result */ $result = new $className($container); if (array_key_exists('modelTemporaryInstance', $config) && $config['modelTemporaryInstance']) { $result = $result->getClone()->savestate(0); } if (array_key_exists('modelClearState', $config) && $config['modelClearState']) { $result->clearState(); } if (array_key_exists('modelClearInput', $config) && $config['modelClearInput']) { $result->clearInput(); } return $result; }
/** * Creates an instance of a controller object. * * @param string $appName The application name [optional] Default: the default application * @param string $controller The controller name [optional] Default: based on the "view" input parameter * @param Container $container The DI container [optional] Default: the application container of the $appName application * * @return Controller A Controller instance * * @throws \RuntimeException When you are referring to a controller class which doesn't exist */ public static function &getInstance($appName = null, $controller = null, $container = null) { if (empty($appName) && !is_object($container)) { $app = Application::getInstance(); $appName = $app->getName(); $container = $app->getContainer(); } elseif (empty($appName) && is_object($container)) { $appName = $container->application_name; } elseif (!empty($appName) && !is_object($container)) { $container = Application::getInstance($appName)->getContainer(); } $input = $container->input; if (empty($controller)) { $controller = $input->getCmd('view', ''); } // Get the class base name, e.g. \Foobar\Controller\ $classBaseName = '\\' . ucfirst($appName) . '\\Controller\\'; // Get the class name suffixes, in the order to be searched for $classSuffixes = array($controller, Inflector::singularize($controller), Inflector::pluralize($controller), 'DefaultController'); // Look for the best classname match foreach ($classSuffixes as $suffix) { $className = $classBaseName . ucfirst($suffix); if (class_exists($className)) { // The class is loaded. We have a match! break; } } if (!class_exists($className)) { throw new \RuntimeException("Controller not found (app : controller) = {$appName} : {$controller}"); } $instance = new $className($container); return $instance; }
/** * Public constructor. Overrides the parent constructor, adding support for database-aware models. * * You can use the $container['mvc_config'] array to pass some configuration values to the object: * * tableName String. The name of the database table to use. Default: #__appName_viewNamePlural (Ruby on Rails convention) * idFieldName String. The table key field name. Default: appName_viewNameSingular_id (Ruby on Rails convention) * knownFields Array. The known fields in the table. Default: read from the table itself * autoChecks Boolean. Should I turn on automatic data validation checks? * fieldsSkipChecks Array. List of fields which should not participate in automatic data validation checks. * aliasFields Array. Associative array of "magic" field aliases. * behavioursDispatcher EventDispatcher. The model behaviours event dispatcher. * behaviourObservers Array. The model behaviour observers to attach to the behavioursDispatcher. * behaviours Array. A list of behaviour names to instantiate and attach to the behavioursDispatcher. * fillable_fields Array. Which fields should be auto-filled from the model state (by extent, the request)? * guarded_fields Array. Which fields should never be auto-filled from the model state (by extent, the request)? * relations Array (hashed). The relations to autoload on model creation. * * Setting either fillable_fields or guarded_fields turns on automatic filling of fields in the constructor. If both * are set only guarded_fields is taken into account. Fields are not filled automatically outside the constructor. * * @see \Awf\Mvc\Model::__construct() * * @param Container $container */ public function __construct(\Awf\Container\Container $container = null) { if (!is_object($container)) { $container = Application::getInstance()->getContainer(); } // First call the parent constructor. It also populates $this->config from $container['mvc_config'] parent::__construct($container); // Should I use a different database object? $this->dbo = $container->db; // Do I have a table name? if (isset($this->config['tableName'])) { $this->tableName = $this->config['tableName']; } elseif (empty($this->tableName)) { // The table name is by default: #__appName_viewNamePlural (Ruby on Rails convention) $viewPlural = Inflector::pluralize($this->getName()); $this->tableName = '#__' . strtolower($this->container->application->getName()) . '_' . strtolower($viewPlural); } // Do I have a table key name? if (isset($this->config['idFieldName'])) { $this->idFieldName = $this->config['idFieldName']; } elseif (empty($this->idFieldName)) { // The default ID field is: appName_viewNameSingular_id (Ruby on Rails convention) $viewSingular = Inflector::singularize($this->getName()); $this->idFieldName = strtolower($this->container->application->getName()) . '_' . strtolower($viewSingular) . '_id'; } // Do I have a list of known fields? if (isset($this->config['knownFields'])) { $this->knownFields = $this->config['knownFields']; } else { // By default the known fields are fetched from the table itself (slow!) $this->knownFields = $this->getTableFields(); } if (empty($this->knownFields)) { throw new NoTableColumns(sprintf('Model %s could not fetch column list for the table %s', $this->getName(), $this->tableName)); } // Should I turn on autoChecks? if (isset($this->config['autoChecks'])) { $this->autoChecks = $this->config['autoChecks']; } // Should I exempt fields from autoChecks? if (isset($this->config['fieldsSkipChecks'])) { $this->fieldsSkipChecks = $this->config['fieldsSkipChecks']; } // Do I have alias fields? if (isset($this->config['aliasFields'])) { $this->aliasFields = $this->config['aliasFields']; } // Do I have a behaviours dispatcher? if (isset($this->config['behavioursDispatcher']) && $this->config['behavioursDispatcher'] instanceof EventDispatcher) { $this->behavioursDispatcher = $this->config['behavioursDispatcher']; } else { $this->behavioursDispatcher = new EventDispatcher($this->container); } // Do I have an array of behaviour observers if (isset($this->config['behaviourObservers']) && is_array($this->config['behaviourObservers'])) { foreach ($this->config['behaviourObservers'] as $observer) { $this->behavioursDispatcher->attach($observer); } } // Do I have a list of behaviours? if (isset($this->config['behaviours']) && is_array($this->config['behaviours'])) { foreach ($this->config['behaviours'] as $behaviour) { $this->addBehaviour($behaviour); } } // Do I have a list of fillable fields? if (isset($this->config['fillable_fields']) && is_array($this->config['fillable_fields'])) { $this->fillable = array(); $this->autoFill = true; foreach ($this->config['fillable_fields'] as $field) { if (array_key_exists($field, $this->knownFields)) { $this->fillable[] = $field; } elseif (isset($this->aliasFields[$field])) { $this->fillable[] = $this->aliasFields[$field]; } } } // Do I have a list of guarded fields? if (isset($this->config['guarded_fields']) && is_array($this->config['guarded_fields'])) { $this->guarded = array(); $this->autoFill = true; foreach ($this->config['guarded_fields'] as $field) { if (array_key_exists($field, $this->knownFields)) { $this->guarded[] = $field; } elseif (isset($this->aliasFields[$field])) { $this->guarded[] = $this->aliasFields[$field]; } } } // Do I have to auto-fill the fields? if ($this->autoFill) { // If I have guarded fields, I'll try to fill everything, using such fields as a "blacklist" if (!empty($this->guarded)) { $fields = array_keys($this->knownFields); } else { // Otherwise I'll fill only the fillable ones (act like having a "whitelist") $fields = $this->fillable; } foreach ($fields as $field) { if (in_array($field, $this->guarded)) { // Do not set guarded fields continue; } $stateValue = $this->getState($field, null); if (!is_null($stateValue)) { $this->setFieldValue($field, $stateValue); } } } // Create a relation manager $this->relationManager = new RelationManager($this); // Do I have a list of relations? if (isset($this->config['relations']) && is_array($this->config['relations'])) { foreach ($this->config['relations'] as $name => $relConfig) { if (!is_array($relConfig)) { continue; } $defaultRelConfig = array('type' => 'hasOne', 'foreignModelClass' => null, 'localKey' => null, 'foreignKey' => null, 'pivotTable' => null, 'pivotLocalKey' => null, 'pivotForeignKey' => null); $relConfig = array_merge($defaultRelConfig, $relConfig); $this->relationManager->addRelation($name, $relConfig['type'], $relConfig['foreignModelClass'], $relConfig['localKey'], $relConfig['foreignKey'], $relConfig['pivotTable'], $relConfig['pivotLocalKey'], $relConfig['pivotForeignKey']); } } // Initialise the data model foreach ($this->knownFields as $fieldName => $information) { // Initialize only the null or not yet set records if (!isset($this->recordData[$fieldName])) { $this->recordData[$fieldName] = $information->Default; } } }
/** * Adds a relation to the relation manager * * @param string $name The name of the relation as known to this relation manager, e.g. 'phone' * @param string $type The relation type, e.g. 'hasOne' * @param string $foreignModelClass The class name of the foreign key's model, e.g. '\Foobar\Phones' * @param string $localKey The local table key for this relation * @param string $foreignKey The foreign key for this relation * @param string $pivotTable For many-to-many relations, the pivot (glue) table * @param string $pivotLocalKey For many-to-many relations, the pivot table's column storing the local key * @param string $pivotForeignKey For many-to-many relations, the pivot table's column storing the foreign key * * @return DataModel The parent model, for chaining * * @throws Relation\Exception\RelationTypeNotFound when $type is not known * @throws Relation\Exception\ForeignModelNotFound when $foreignModelClass doesn't exist */ public function addRelation($name, $type, $foreignModelClass = null, $localKey = null, $foreignKey = null, $pivotTable = null, $pivotLocalKey = null, $pivotForeignKey = null) { if (!isset(static::$relationTypes[$type])) { throw new DataModel\Relation\Exception\RelationTypeNotFound("Relation type '{$type}' not found"); } // Guess the foreign model class if necessary if (empty($foreignModelClass) || !class_exists($foreignModelClass, true)) { $parentClass = get_class($this->parentModel); $classNameParts = explode('\\', $parentClass); array_pop($classNameParts); $classPrefix = implode('\\', $classNameParts); $foreignModelClass = $classPrefix . '\\' . ucfirst($name); if (!class_exists($foreignModelClass, true)) { $foreignModelClass = $classPrefix . '\\' . ucfirst(Inflector::pluralize($name)); } } if (!class_exists($foreignModelClass, true)) { throw new DataModel\Relation\Exception\ForeignModelNotFound("Foreign model '{$foreignModelClass}' for relation '{$name}' not found"); } $className = static::$relationTypes[$type]; /** @var Relation $relation */ $relation = new $className($this->parentModel, $foreignModelClass, $localKey, $foreignKey, $pivotTable, $pivotLocalKey, $pivotForeignKey); $this->relations[$name] = $relation; return $this->parentModel; }
/** * Delete selected item(s) * * @return void */ public function remove() { // CSRF prevention $this->csrfProtection(); $model = $this->getModel(); $ids = $this->getIDsFromRequest($model, false); try { $status = true; foreach ($ids as $id) { $model->find($id); $model->delete(); } } catch (\Exception $e) { $status = false; $error = $e->getMessage(); } // Redirect if ($customURL = $this->input->getBase64('returnurl', '')) { $customURL = base64_decode($customURL); } $router = $this->container->router; $url = !empty($customURL) ? $customURL : $router->route('index.php?view=' . Inflector::pluralize($this->view)); if (!$status) { $this->setRedirect($url, $error, 'error'); } else { $textKey = $this->container->application_name . '_LBL_' . Inflector::singularize($this->view) . '_DELETED'; $this->setRedirect($url, Text::_($textKey)); } }