public function __construct($container = null) { if (!is_object($container)) { $container = Application::getInstance()->getContainer(); } parent::__construct(); $config = $container->appConfig; $smtpauth = $config->get('mail.smtpauth') == 0 ? null : 1; $smtpuser = $config->get('mail.smtpuser'); $smtppass = $config->get('mail.smtppass'); $smtphost = $config->get('mail.smtphost'); $smtpsecure = $config->get('mail.smtpsecure'); $smtpport = $config->get('mail.smtpport'); $mailfrom = $config->get('mail.mailfrom'); $fromname = $config->get('mail.fromname'); $mailer = $config->get('mail.mailer'); $this->SetFrom($mailfrom, $fromname); $this->container = $container; switch ($mailer) { case 'smtp': $this->useSMTP($smtpauth, $smtphost, $smtpuser, $smtppass, $smtpsecure, $smtpport); break; case 'sendmail': $this->IsSendmail(); break; default: $this->IsMail(); break; } }
/** * Public constructor. Creates a new User Manager. Do not call this directly. It's best to call getInstance() * instead. * * @param Container $container */ public function __construct(Container $container = null) { if (!is_object($container)) { $container = Application::getInstance()->getContainer(); } $this->user_table = $container->appConfig->get('user_table', '#__users'); $this->user_class = $container->appConfig->get('user_class', '\\Awf\\User\\User'); $this->container = $container; }
/** * Constructor. * * @param integer $total The total number of items. * @param integer $limitStart The offset of the item to start at. * @param integer $limit The number of items to display per page. * @param integer $displayed Maximum number of page links to display (default: 10) * @param Application $app The application this pagination object is attached to */ public function __construct($total, $limitStart, $limit, $displayed = 10, $app = null) { if (!is_object($app) || !$app instanceof Application) { $app = Application::getInstance(); } $this->application = $app; // Value/type checking. $this->total = (int) $total; $this->limitStart = (int) max($limitStart, 0); $this->limit = (int) max($limit, 0); if ($this->limit > $this->total) { $this->limitStart = 0; } if (!$this->limit) { $this->limit = $total; $this->limitStart = 0; } /* * If limitStart is greater than total (i.e. we are asked to display records that don't exist) * then set limitStart to display the last natural page of results */ if ($this->limitStart > $this->total - $this->limit) { $this->limitStart = max(0, (int) (ceil($this->total / $this->limit) - 1) * $this->limit); } // Set the total pages and current page values. if ($this->limit > 0) { $this->pagesTotal = ceil($this->total / $this->limit); $this->pagesCurrent = ceil(($this->limitStart + 1) / $this->limit); } // Set the pagination iteration loop values. $this->pagesDisplayed = $displayed; $displayedPages = $this->pagesDisplayed; $this->pagesStart = $this->pagesCurrent - $displayedPages / 2; if ($this->pagesStart < 1) { $this->pagesStart = 1; } if ($this->pagesStart + $displayedPages > $this->pagesTotal) { $this->pagesStop = $this->pagesTotal; if ($this->pagesTotal < $displayedPages) { $this->pagesStart = 1; } else { $this->pagesStart = $this->pagesTotal - $displayedPages + 1; } } else { $this->pagesStop = $this->pagesStart + $displayedPages - 1; } // If we are viewing all records set the view all flag to true. if ($limit == 0) { $this->viewAll = true; } // Automatically set the URL parameters $this->setAdditionalUrlParamsFromInput(); }
/** * Checks for snooping outside of the file system root. * * @param string $path A file system path to check. * @param string $ds Directory separator (optional). * * @return string A cleaned version of the path or exit on error. * * @throws \Exception When malicious activity is detected */ public static function check($path, $ds = DIRECTORY_SEPARATOR) { if (strpos($path, '..') !== false) { // Don't translate throw new \Exception(__CLASS__ . '::check Use of relative paths not permitted', 20); } $rootPath = Application::getInstance()->getContainer()->filesystemBase; $path = self::clean($path); if ($rootPath != '' && strpos($path, self::clean($rootPath)) !== 0) { // Don't translate throw new \Exception(__CLASS__ . '::check Snooping out of bounds @ ' . $path, 20); } return $path; }
/** * Add unobtrusive JavaScript support for a calendar control. * * @param Application $app CSS and JS will be added to the document of the selected application * * @return void */ public static function calendar(Application $app = null) { // Only load once if (isset(static::$loaded[__METHOD__])) { return; } if (!is_object($app)) { $app = Application::getInstance(); } $document = $app->getDocument(); Template::addJs('media://js/datepicker/bootstrap-datepicker.js'); Template::addCss('media://css/datepicker.css'); static::$loaded[__METHOD__] = true; }
/** * Public constructor * * @param Container $container The container this dispatcher belongs to */ public function __construct($container = null) { if (!is_object($container) || !$container instanceof Container) { $container = Application::getInstance()->getContainer(); } $this->container = $container; $this->input = $container->input; // Get the default values for the view and layout names $this->view = $this->input->getCmd('view', null); $this->layout = $this->input->getCmd('layout', null); // Not redundant; you may pass an empty but non-null view which is invalid, so we need the fallback if (empty($this->view)) { $this->view = $this->defaultView; $this->container->input->set('view', $this->view); } }
/** * Public constructor. Initialises the relation. * * @param DataModel $parentModel The data model we are attached to * @param string $foreignModelClass The class name of the foreign key's model * @param string $localKey The local table key for this relation, default: parentModel's ID field name * @param string $foreignKey The foreign key for this relation, default: parentModel's ID field name * @param string $pivotTable IGNORED * @param string $pivotLocalKey IGNORED * @param string $pivotForeignKey IGNORED */ public function __construct(DataModel $parentModel, $foreignModelClass, $localKey = null, $foreignKey = null, $pivotTable = null, $pivotLocalKey = null, $pivotForeignKey = null) { parent::__construct($parentModel, $foreignModelClass, $localKey, $foreignKey, $pivotTable, $pivotLocalKey, $pivotForeignKey); if (empty($localKey)) { // Get a model instance $container = Application::getInstance($this->foreignModelApp)->getContainer(); /** @var DataModel $foreignModel */ $foreignModel = DataModel::getTmpInstance($this->foreignModelApp, $this->foreignModelName, $container); $this->localKey = $foreignModel->getIdFieldName(); } if (empty($foreignKey)) { if (!isset($foreignModel)) { // Get a model instance $container = Application::getInstance($this->foreignModelApp)->getContainer(); /** @var DataModel $foreignModel */ $foreignModel = DataModel::getTmpInstance($this->foreignModelApp, $this->foreignModelName, $container); } $this->foreignKey = $foreignModel->getIdFieldName(); } }
/** * Public constructor * * @param Container $container The container attached to this application * * @return Cli */ public function __construct(Container $container = null) { // Close the application if we are not executed from the command line, Akeeba style (allow for PHP CGI) if (array_key_exists('REQUEST_METHOD', $_SERVER)) { die('You are not supposed to access this script from the web. You have to run it from the command line.'); } if (empty($container['application_name'])) { $container->application_name = 'cli'; $this->name = 'cli'; } parent::__construct($container); if (!$container->input instanceof \Awf\Input\Cli) { // Create an input object $cgiMode = false; if (!defined('STDOUT') || !defined('STDIN') || !isset($_SERVER['argv'])) { $cgiMode = true; } if ($cgiMode) { $query = ""; if (!empty($_GET)) { foreach ($_GET as $k => $v) { $query .= " {$k}"; if ($v != "") { $query .= "={$v}"; } } } $query = ltrim($query); $argv = explode(' ', $query); $argc = count($argv); $_SERVER['argv'] = $argv; } unset($container['input']); $container['input'] = new \Awf\Input\Cli(); try { } catch (\Exception $e) { } } self::$instances['cli'] = $this; }
/** * Get a filesystem abstraction adapter based on the configuration of the provided application object * * @param Container $container The application which provides the configuration * @param boolean $hybrid Should I return a hybrid adapter? * * @return FilesystemInterface The filesystem abstraction adapter */ public static function getAdapter(Container $container = null, $hybrid = false) { if (!is_object($container)) { $container = Application::getInstance()->getContainer(); } $config = $container->appConfig; $defaultPort = $config->get('fs.driver', 'file') == 'ftp' ? '21' : '22'; $options = array('driver' => $config->get('fs.driver', 'file'), 'host' => $config->get('fs.host', 'localhost'), 'port' => $config->get('fs.port', $defaultPort), 'username' => $config->get('fs.username', ''), 'password' => $config->get('fs.password', ''), 'directory' => $config->get('fs.dir', ''), 'ssl' => $config->get('fs.ssl', false), 'passive' => $config->get('fs.passive', true)); $classPrefix = '\\Awf\\Filesystem\\'; $className = $classPrefix . ucfirst($options['driver']); if (!class_exists($className)) { $hybrid = false; $className = $classPrefix . 'File'; } elseif ($hybrid) { $className = $classPrefix . 'Hybrid'; } $signature = md5($container->application_name . $className . ($hybrid ? 'hybrid' : '')); if (!isset(self::$instances[$signature])) { self::$instances[$signature] = new $className($options); } return self::$instances[$signature]; }
/** * Returns a new item of the foreignModel type, pre-initialised to fulfil this relation * * @return DataModel * * @throws DataModel\Relation\Exception\NewNotSupported when it's not supported */ public function getNew() { // Get a model instance $container = Application::getInstance($this->foreignModelApp)->getContainer(); /** @var DataModel $foreignModel */ $foreignModel = DataModel::getTmpInstance($this->foreignModelApp, $this->foreignModelName, $container); // Prime the model $foreignModel->setFieldValue($this->foreignKey, $this->parentModel->getFieldValue($this->localKey)); // Make sure we do have a data list if (!$this->data instanceof Collection) { $this->getData(); } // Add the model to the data list $this->data->add($foreignModel); return $this->data->last(); }
/** * Automatically detect the language preferences from the browser, choosing * the best fit language that exists on our system or falling back to en-GB * when no preferred language exists. * * @param string $appName The application's name to load language strings for * @param string $suffix The suffix of the language file, by default it's .ini * @param string $languagePath The base path to the language files (optional) * * @return string The language code */ public static function detectLanguage($appName = null, $suffix = '.ini', $languagePath = null) { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $languages = strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]); // $languages = ' fr-ch;q=0.3, da, en-us;q=0.8, en;q=0.5, fr;q=0.3'; // need to remove spaces from strings to avoid error $languages = str_replace(' ', '', $languages); $languages = explode(",", $languages); // First we need to sort languages by their weight $temp = array(); foreach ($languages as $lang) { $parts = explode(';', $lang); $q = 1; if (count($parts) > 1 && substr($parts[1], 0, 2) == 'q=') { $q = floatval(substr($parts[1], 2)); } $temp[$parts[0]] = $q; } arsort($temp); $languages = $temp; foreach ($languages as $language => $weight) { // pull out the language, place languages into array of full and primary // string structure: $temp_array = array(); // slice out the part before the dash, place into array $temp_array[0] = $language; //full language $parts = explode('-', $language); $temp_array[1] = $parts[0]; // cut out primary language if (strlen($temp_array[0]) == 5 && (substr($temp_array[0], 2, 1) == '-' || substr($temp_array[0], 2, 1) == '_')) { $langLocation = strtoupper(substr($temp_array[0], 3, 2)); $temp_array[0] = $temp_array[1] . '-' . $langLocation; } //place this array into main $user_languages language array $user_languages[] = $temp_array; } if (!isset($user_languages)) { return 'en-GB'; } if (empty($appName)) { $appName = Application::getInstance()->getName(); } if (empty($languagePath)) { $languagePath = Application::getInstance($appName)->getContainer()->languagePath; } $baseName = $languagePath . '/' . strtolower($appName) . '/'; if (!@is_dir($baseName)) { $baseName = $languagePath . '/'; } if (!@is_dir($baseName)) { return 'en-GB'; } // Look for classic file layout foreach ($user_languages as $languageStruct) { // Search for exact language $langFilename = $baseName . $languageStruct[0] . $suffix; if (!file_exists($langFilename)) { $langFilename = ''; $filesystem = new File(array()); $allFiles = $filesystem->directoryFiles($baseName, $languageStruct[1] . '\\-.*', false, true); if (count($allFiles)) { $langFilename = array_shift($allFiles); } } if (!empty($langFilename) && file_exists($langFilename)) { return basename($langFilename, $suffix); } } // Look for subdirectory layout $allFolders = array(); try { $di = new \DirectoryIterator($baseName); } catch (\Exception $e) { return 'en-GB'; } /** @var \DirectoryIterator $file */ foreach ($di as $file) { if ($di->isDot()) { continue; } if (!$di->isDir()) { continue; } $allFolders[] = $file->getFilename(); } foreach ($user_languages as $languageStruct) { if (array_key_exists($languageStruct[0], $allFolders)) { return $languageStruct[0]; } foreach ($allFolders as $folder) { if (strpos($folder, $languageStruct[1]) === 0) { return $folder; } } } } return 'en-GB'; }
/** * Method to return a Driver instance based on the given options. There are three global options and then * the rest are specific to the database driver. The 'driver' option defines which Driver class is * used for the connection -- the default is 'mysqli'. The 'database' option determines which database is to * be used for the connection. The 'select' option determines whether the connector should automatically select * the chosen database. * * Instances are unique to the given options and new objects are only created when a unique options array is * passed into the method. This ensures that we don't end up with unnecessary database connection resources. * * @param array|Container $options Parameters to be passed to the database driver or a DI Container to read app * config from. * * @return Driver A database object. * * @throws \RuntimeException When the driver cannot be instantiated */ public static function getInstance($options = array()) { // If no options are passed, push the default application into the options. This will result in the // default driver object instance for the app to be created. if (empty($options)) { $options = Application::getInstance()->getContainer(); } // If an application is passed in the options ignore everything else and set up based on app configuration if (is_object($options) && $options instanceof Container) { $config = $options->appConfig; $options = array('driver' => $config->get('dbdriver', 'mysqli'), 'database' => $config->get('dbname', 'solo'), 'select' => true, 'host' => $config->get('dbhost', 'localhost'), 'user' => $config->get('dbuser', ''), 'password' => $config->get('dbpass', ''), 'prefix' => $config->get('prefix', 'solo_')); } // Sanitize the database connector options. $options['driver'] = isset($options['driver']) ? preg_replace('/[^A-Z0-9_\\.-]/i', '', $options['driver']) : 'mysqli'; $options['database'] = isset($options['database']) ? $options['database'] : null; $options['select'] = isset($options['select']) ? $options['select'] : true; // Get the options signature for the database connector. $signature = md5(serialize($options)); // If we already have a database connector instance for these options then just use that. if (empty(self::$instances[$signature])) { // Derive the class name from the driver. $class = '\\Awf\\Database\\Driver\\' . ucfirst(strtolower($options['driver'])); // If the class still doesn't exist we have nothing left to do but throw an exception. We did our best. if (!class_exists($class)) { throw new \RuntimeException(sprintf('Unable to load Database Driver: %s', $options['driver'])); } // Create our new Driver connector based on the options given. try { $instance = new $class($options); } catch (\RuntimeException $e) { throw new \RuntimeException(sprintf('Unable to connect to the Database: %s', $e->getMessage())); } // Set the new connector to the global instances based on signature. self::$instances[$signature] = $instance; } return self::$instances[$signature]; }
/** * Redirects the browser or returns false if no redirect is set. * * @return boolean False if no redirect exists. */ public function redirect() { if ($this->redirect) { $app = Application::getInstance(); $app->redirect($this->redirect, $this->message, $this->messageType); } return false; }
/** * Returns the count subquery for DataModel's has() and whereHas() methods. * * @return Query */ public function getCountSubquery() { // Get a model instance $container = Application::getInstance($this->foreignModelApp)->getContainer(); /** @var DataModel $foreignModel */ $foreignModel = DataModel::getTmpInstance($this->foreignModelApp, $this->foreignModelName, $container); $db = $foreignModel->getDbo(); $query = $db->getQuery(true)->select('COUNT(*)')->from($db->qn($foreignModel->getTableName()) . ' AS ' . $db->qn('reltbl'))->innerJoin($db->qn($this->pivotTable) . ' AS ' . $db->qn('pivotTable') . ' ON(' . $db->qn('pivotTable') . '.' . $db->qn($this->pivotForeignKey) . ' = ' . $db->qn('reltbl') . '.' . $db->qn($foreignModel->getFieldAlias($this->foreignKey)) . ')')->where($db->qn('pivotTable') . '.' . $db->qn($this->pivotLocalKey) . ' =' . $db->qn($this->parentModel->getTableName()) . '.' . $db->qn($this->parentModel->getFieldAlias($this->localKey))); return $query; }
/** * Performs the staggered download of file. * * @param array $params A parameters array, as sent by the user interface * * @return array A return status array */ public function importFromURL($params) { $this->params = $params; // Fetch data $filename = $this->getParam('file'); $frag = $this->getParam('frag', -1); $totalSize = $this->getParam('totalSize', -1); $doneSize = $this->getParam('doneSize', -1); $maxExecTime = $this->getParam('maxExecTime', 5); $runTimeBias = $this->getParam('runTimeBias', 75); $minExecTime = $this->getParam('minExecTime', 1); $localFilename = 'download.zip'; $tmpDir = Application::getInstance()->getContainer()->temporaryPath; $tmpDir = rtrim($tmpDir, '/\\'); $localFilename = $this->getParam('localFilename', $localFilename); // Init retArray $retArray = array("status" => true, "error" => '', "frag" => $frag, "totalSize" => $totalSize, "doneSize" => $doneSize, "percent" => 0); try { $timer = new Timer($minExecTime, $runTimeBias); $start = $timer->getRunningTime(); // Mark the start of this download $break = false; // Don't break the step // Figure out where on Earth to put that file $local_file = $tmpDir . '/' . $localFilename; //debugMsg("- Importing from $filename"); while ($timer->getTimeLeft() > 0 && !$break) { // Do we have to initialize the file? if ($frag == -1) { //debugMsg("-- First frag, killing local file"); // Currently downloaded size $doneSize = 0; if (@file_exists($local_file)) { @unlink($local_file); } // Delete and touch the output file $fp = @fopen($local_file, 'wb'); if ($fp !== false) { @fclose($fp); } // Init $frag = 0; //debugMsg("-- First frag, getting the file size"); $retArray['totalSize'] = $this->adapter->getFileSize($filename); $totalSize = $retArray['totalSize']; } // Calculate from and length $length = 1048576; $from = $frag * $length; $to = $length + $from - 1; // Try to download the first frag $required_time = 1.0; //debugMsg("-- Importing frag $frag, byte position from/to: $from / $to"); try { $result = $this->adapter->downloadAndReturn($filename, $from, $to); if ($result === false) { throw new \Exception(Text::sprintf('AWF_DOWNLOAD_ERR_LIB_COULDNOTDOWNLOADFROMURL', $filename), 500); } } catch (\Exception $e) { $result = false; $error = $e->getMessage(); } if ($result === false) { // Failed download if ($frag == 0) { // Failure to download first frag = failure to download. Period. $retArray['status'] = false; $retArray['error'] = $error; //debugMsg("-- Download FAILED"); return $retArray; } else { // Since this is a staggered download, consider this normal and finish $frag = -1; //debugMsg("-- Import complete"); $totalSize = $doneSize; $break = true; } } // Add the currently downloaded frag to the total size of downloaded files if ($result) { $filesize = strlen($result); //debugMsg("-- Successful download of $filesize bytes"); $doneSize += $filesize; // Append the file $fp = @fopen($local_file, 'ab'); if ($fp === false) { //debugMsg("-- Can't open local file $local_file for writing"); // Can't open the file for writing $retArray['status'] = false; $retArray['error'] = Text::sprintf('AWF_DOWNLOAD_ERR_LIB_COULDNOTWRITELOCALFILE', $local_file); return $retArray; } fwrite($fp, $result); fclose($fp); //debugMsg("-- Appended data to local file $local_file"); $frag++; //debugMsg("-- Proceeding to next fragment, frag $frag"); if ($filesize < $length || $filesize > $length) { // A partial download or a download larger than the frag size means we are done $frag = -1; //debugMsg("-- Import complete (partial download of last frag)"); $totalSize = $doneSize; $break = true; } } // Advance the frag pointer and mark the end $end = $timer->getRunningTime(); // Do we predict that we have enough time? $required_time = max(1.1 * ($end - $start), $required_time); if ($required_time > 10 - $end + $start) { $break = true; } $start = $end; } if ($frag == -1) { $percent = 100; } elseif ($doneSize <= 0) { $percent = 0; } else { if ($totalSize > 0) { $percent = 100 * ($doneSize / $totalSize); } else { $percent = 0; } } // Update $retArray $retArray = array("status" => true, "error" => '', "frag" => $frag, "totalSize" => $totalSize, "doneSize" => $doneSize, "percent" => $percent); } catch (\Exception $e) { //debugMsg("EXCEPTION RAISED:"); //debugMsg($e->getMessage()); $retArray['status'] = false; $retArray['error'] = $e->getMessage(); } return $retArray; }
/** * Get the relation data. * * If you want to apply additional filtering to the foreign model, use the $callback. It can be any function, * static method, public method or closure with an interface of function(DataModel $foreignModel). You are not * supposed to return anything, just modify $foreignModel's state directly. For example, you may want to do: * $foreignModel->setState('foo', 'bar') * * @param callable $callback The callback to run on the remote model. * @param Collection $dataCollection * * @return Collection|DataModel */ public function getData(callable $callback = null, Collection $dataCollection = null) { if (is_null($this->data)) { // Initialise $this->data = new Collection(); // Get a model instance $container = Application::getInstance($this->foreignModelApp)->getContainer(); /** @var DataModel $foreignModel */ $foreignModel = DataModel::getTmpInstance($this->foreignModelApp, $this->foreignModelName, $container)->setIgnoreRequest(true); $filtered = $this->filterForeignModel($foreignModel, $dataCollection); if (!$filtered) { return $this->data; } // Apply the callback, if applicable if (!is_null($callback) && is_callable($callback)) { call_user_func($callback, $foreignModel); } // Get the list of items from the foreign model and cache in $this->data $this->data = $foreignModel->get(true); } return $this->data; }
public function __construct(array $values = array()) { $this->application_name = ''; $this->session_segment_name = null; $this->basePath = null; $this->templatePath = null; $this->languagePath = null; $this->temporaryPath = null; $this->filesystemBase = null; $this->sqlPath = null; parent::__construct($values); // Application service if (!isset($this['application'])) { $this['application'] = function (Container $c) { return Application::getInstance($c->application_name, $c); }; } // Application Configuration service if (!isset($this['appConfig'])) { $this['appConfig'] = function (Container $c) { return new \Awf\Application\Configuration($c); }; } // Database Driver service if (!isset($this['db'])) { $this['db'] = function (Container $c) { return Driver::getInstance($c); }; } // Application Dispatcher service if (!isset($this['dispatcher'])) { $this['dispatcher'] = function (Container $c) { $className = '\\' . ucfirst($c->application_name) . '\\Dispatcher'; if (!class_exists($className)) { $className = '\\Awf\\Dispatcher\\Dispatcher'; } return new $className($c); }; } // Application Event Dispatcher service if (!isset($this['eventDispatcher'])) { $this['eventDispatcher'] = function (Container $c) { return new \Awf\Event\Dispatcher($c); }; } // Filesystem Abstraction Layer service if (!isset($this['fileSystem'])) { $this['fileSystem'] = function (Container $c) { return \Awf\Filesystem\Factory::getAdapter($c, true); }; } // Input Access service if (!isset($this['input'])) { $this['input'] = function (Container $c) { return new \Awf\Input\Input(); }; } // Mailer Object service if (!isset($this['mailer'])) { $this['mailer'] = $this->factory(function (Container $c) { return new \Awf\Mailer\Mailer($c); }); } // Application Router service if (!isset($this['router'])) { $this['router'] = function (Container $c) { return new \Awf\Router\Router($c); }; } // Session Manager service if (!isset($this['session'])) { $this['session'] = function () { return new Session\Manager(new Session\SegmentFactory(), new Session\CsrfTokenFactory(new Session\Randval(new Phpfunc())), $_COOKIE); }; } // Application Session Segment service if (!isset($this['segment'])) { $this['segment'] = function (Container $c) { if (empty($c->session_segment_name)) { $c->session_segment_name = 'Akeeba\\Awf\\' . $c->application_name; } return $c->session->newSegment($c->session_segment_name); }; } // User Manager service if (!isset($this['userManager'])) { $this['userManager'] = function (Container $c) { return new \Awf\User\Manager($c); }; } }
/** * 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; } } }
/** * Displays a calendar control field * * @param string $value The date value * @param string $name The name of the text field * @param string $id The id of the text field * @param string $format The date format * @param array $attribs Additional HTML attributes * @param Application $app The application to get the configuration from * * @return string HTML markup for a calendar field */ public static function calendar($value, $name, $id, $format = 'yyyy-mm-dd', $attribs = null, Application $app = null) { static $done; if (!is_object($app)) { $app = Application::getInstance(); } if ($done === null) { $done = array(); } $attribs['class'] = isset($attribs['class']) ? $attribs['class'] : 'form-control'; $attribs['class'] = trim($attribs['class'] . ' hasTooltip calendar'); $readonly = isset($attribs['readonly']) && $attribs['readonly'] == 'readonly'; $disabled = isset($attribs['disabled']) && $attribs['disabled'] == 'disabled'; if (is_array($attribs)) { $attribs = ArrayHelper::toString($attribs); } if (!$readonly && !$disabled) { // Load the calendar behavior Behaviour::calendar(); // Only display the triggers once for each control. if (!in_array($id, $done)) { // @todo Implement a way for the application to override the language $lang = Text::detectLanguage($app->getName()); $document = $app->getDocument(); $document->addScriptDeclaration(<<<JS akeeba.jQuery(document).ready(function(){ \takeeba.jQuery('#{$id}-container').datepicker({ \t\tformat: "{$format}", \t\ttodayBtn: "linked", \t\tlanguage: "{$lang}", \t\tautoclose: true \t}); }) JS ); $done[] = $id; } return '<div class="input-group date" id="' . $id . '-container"><input type="text" title="' . (0 !== (int) $value ? static::date($value, null, null) : '') . '" name="' . $name . '" id="' . $id . '" value="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '" ' . $attribs . ' />' . '<span class="input-group-btn" id="' . $id . '_img"><span class="btn btn-default"><span class="glyphicon glyphicon-calendar"></span></span></span></div>'; } else { return '<input type="text" title="' . (0 !== (int) $value ? static::date($value, null, null) : '') . '" value="' . (0 !== (int) $value ? static::_('date', $value, 'Y-m-d H:i:s', null) : '') . '" ' . $attribs . ' /><input type="hidden" name="' . $name . '" id="' . $id . '" value="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '" />'; } }
/** * Parse a fancy path definition into a path relative to the site's root. * It returns both the normal and alternative (template media override) path. * For example, media://com_foobar/css/test.css is parsed into * array( * 'normal' => 'media/com_foobar/css/test.css', * 'alternate' => 'templates/mytemplate/media/com_foobar/css//test.css' * ); * * The valid protocols are: * media:// The media directory or a media override * site:// Path relative to site's root (no alternate) * * @param string $path Fancy path * @param Application $app The application we're operating under * * @return array Array of normal and alternate parsed path */ public static function getAltPaths($path, $app = null) { if (!is_object($app)) { $app = Application::getInstance(); } $protoAndPath = explode('://', $path, 2); if (count($protoAndPath) < 2) { $protocol = 'media'; } else { $protocol = $protoAndPath[0]; $path = $protoAndPath[1]; } $path = ltrim($path, '/' . DIRECTORY_SEPARATOR); switch ($protocol) { case 'media': // Do we have a media override in the template? $pathAndParams = explode('?', $path, 2); // Get the path of the templates directory relative to the file system base $rootPath = realpath($app->getContainer()->filesystemBase); $templateRelativePath = realpath($app->getContainer()->templatePath); if ($templateRelativePath == $rootPath) { $templateRelativePath = ''; } elseif (strpos($templateRelativePath, $rootPath) === 0) { $templateRelativePath = substr($templateRelativePath, strlen($rootPath)); $templateRelativePath = trim($templateRelativePath, DIRECTORY_SEPARATOR . '/\\') . '/'; } $templateRelativePath = str_replace('\\', '/', $templateRelativePath); // Return the alternative paths $ret = array('normal' => 'media/' . $pathAndParams[0], 'alternate' => $templateRelativePath . $app->getTemplate() . '/media/' . $pathAndParams[0]); break; default: case 'site': $ret = array('normal' => $path); break; } // For CSS and JS files, add a debug path if the supplied file is compressed $ext = pathinfo($ret['normal'], PATHINFO_EXTENSION); if (in_array($ext, array('css', 'js'))) { $file = basename($ret['normal'], '.' . $ext); if (strlen($file) > 4 && strrpos($file, '.min', '-4')) { $position = strrpos($file, '.min', '-4'); $filename = str_replace('.min', '.', $file, $position) . $ext; } else { $filename = $file . '-uncompressed.' . $ext; } // Clone the $ret array so we can manipulate the 'normal' path a bit $t1 = (object) $ret; $temp = clone $t1; unset($t1); $temp = (array) $temp; $normalPath = explode('/', $temp['normal']); array_pop($normalPath); $normalPath[] = $filename; $ret['debug'] = implode('/', $normalPath); } return $ret; }
/** * Public class constructor * * You can use the $container['mvc_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 now automatically load state data from the request. * * @param Container $container The configuration variables to this model */ public function __construct(\Awf\Container\Container $container = null) { if (!is_object($container)) { $container = Application::getInstance()->getContainer(); } $this->input = $container->input; $this->container = $container; $this->config = isset($container['mvc_config']) ? $container['mvc_config'] : array(); // Set the model's name $this->name = $this->getName(); // Set the model state if (array_key_exists('state', $this->config)) { if (is_object($this->config['state'])) { $this->state = $this->config['state']; } elseif (is_array($this->config['state'])) { $this->state = (object) $this->config['state']; } else { $this->state = new \stdClass(); } } else { $this->state = new \stdClass(); } // Set the internal state marker if (!empty($this->config['use_populate'])) { $this->_state_set = true; } // Set the internal state marker if (!empty($this->config['ignore_request'])) { $this->_ignoreRequest = true; } }
/** * Loads a template given any path. The path is in the format: * viewname/templatename * * @param string $path The template path * @param array $forceParams A hash array of variables to be extracted in the local scope of the template file * * @return string The output of the template * * @throws \Exception When the layout file is not found */ public function loadAnyTemplate($path = '', $forceParams = array()) { $template = \Awf\Application\Application::getInstance()->getTemplate(); $layoutTemplate = $this->getLayoutTemplate(); // Parse the path $templateParts = $this->parseTemplatePath($path); // Get the default paths $templatePath = $this->container->templatePath; $paths = array(); $paths[] = $templatePath . '/' . $template . '/html/' . $this->input->getCmd('option', '') . '/' . $templateParts['view']; $paths[] = $this->container->basePath . '/views/' . $templateParts['view'] . '/tmpl'; $paths[] = $this->container->basePath . '/View/' . $templateParts['view'] . '/tmpl'; $paths = array_merge($paths, $this->templatePaths); // Look for a template override if (isset($layoutTemplate) && $layoutTemplate != '_' && $layoutTemplate != $template) { $apath = array_shift($paths); array_unshift($paths, str_replace($template, $layoutTemplate, $apath)); } $filetofind = $templateParts['template'] . '.php'; $this->_tempFilePath = \Awf\Utils\Path::find($paths, $filetofind); if ($this->_tempFilePath) { // Unset from local scope unset($template); unset($layoutTemplate); unset($paths); unset($path); unset($filetofind); // Never allow a 'this' property if (isset($this->this)) { unset($this->this); } // Force parameters into scope if (!empty($forceParams)) { extract($forceParams); } // Start capturing output into a buffer ob_start(); // Include the requested template filename in the local scope // (this will execute the view logic). include $this->_tempFilePath; // Done with the requested template; get the buffer and // clear it. $this->output = ob_get_contents(); ob_end_clean(); return $this->output; } else { return new \Exception(\Awf\Text\Text::sprintf('AWF_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $path), 500); } }
/** * Returns the base URI for the request. * * @param boolean $pathonly If false, prepend the scheme, host and port information. Default is false. * @param Container $container The container to use for determining the live_site configuration value * * @return string The base URI string */ public static function base($pathonly = false, Container $container = null) { // Get the base request path. if (empty(self::$base)) { if (!is_object($container)) { $container = Application::getInstance()->getContainer(); } $config = $container->appConfig; $live_site = $config->get('live_site'); if (trim($live_site) != '') { $uri = self::getInstance($live_site); self::$base['prefix'] = $uri->toString(array('scheme', 'host', 'port')); self::$base['path'] = rtrim($uri->toString(array('path')), '/\\'); } else { $uri = self::getInstance(); self::$base['prefix'] = $uri->toString(array('scheme', 'host', 'port')); if (strpos(php_sapi_name(), 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI'])) { // PHP-CGI on Apache with "cgi.fix_pathinfo = 0" // We shouldn't have user-supplied PATH_INFO in PHP_SELF in this case // because PHP will not work with PATH_INFO at all. $script_name = $_SERVER['PHP_SELF']; } else { // Others $script_name = $_SERVER['SCRIPT_NAME']; } self::$base['path'] = rtrim(dirname($script_name), '/\\'); } } return $pathonly === false ? self::$base['prefix'] . self::$base['path'] . '/' : self::$base['path']; }