File: /var/www/apklausos/application/models/Template.php
<?php
/*
* LimeSurvey
* Copyright (C) 2007-2011 The LimeSurvey Project Team / Carsten Schmitz
* All rights reserved.
* License: GNU/GPL License v2 or later, see LICENSE.php
* LimeSurvey is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*
*/
/**
* Class Template
*
* @property string $name Template name
* @property string $folder Template folder name eg: 'default'
* @property string $title
* @property string $creation_date
* @property string $author
* @property string $author_email
* @property string $author_url
* @property string $copyright
* @property string $license
* @property string $version
* @property string $view_folder
* @property string $files_folder
* @property string $description
* @property string $last_update
* @property string $api_version
* @property integer $owner_id
* @property string $extends
*/
class Template extends LSActiveRecord
{
/** @var array $aAllTemplatesDir cache for the method getAllTemplatesDirectories */
public static $aAllTemplatesDir = null;
/** @var array $aTemplatesFileFolder cache for the method getTemplateFilesFolder */
public static $aTemplatesFileFolder = null;
/** @var array $aNamesFiltered cache for the method templateNameFilter */
public static $aNamesFiltered = null;
/** @var Template - The instance of template object */
private static $instance;
public static $sTemplateNameIllegalChars = "#$%^&*()+=[]';,./{}|:<>?~";
/**
* @return string the associated database table name
*/
public function tableName()
{
return '{{templates}}';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('name', 'checkTemplateName'),
array('title, creation_date', 'required'),
array('owner_id', 'numerical', 'integerOnly' => true),
array('name, author, extends', 'length', 'max' => 150),
array('folder, version, api_version, view_folder, files_folder', 'length', 'max' => 45),
array('title', 'length', 'max' => 100),
array('author_email, author_url', 'length', 'max' => 255),
array('copyright, license, description, last_update', 'safe'),
// The following rule is used by search().
// @todo Please remove those attributes that should not be searched.
array('name, folder, title, creation_date, author, author_email, author_url, copyright, license, version, api_version, view_folder, files_folder, description, last_update, owner_id, extends', 'safe', 'on' => 'search'),
);
}
/**
* Template name rule function.
*/
public function checkTemplateName($attributes, $params)
{
Template::validateTemplateName($this->name);
return true;
}
/**
* Validate the template name.
*
* @param string $templateName The name of the template
*/
public static function validateTemplateName($templateName)
{
if (strpbrk((string) $templateName, Template::$sTemplateNameIllegalChars)) {
Yii::app()->setFlashMessage(sprintf(gT("The name contains special characters.")), 'error');
Yii::app()->getController()->redirect(array('themeOptions/index'));
Yii::app()->end();
} elseif (strlen((string)$templateName) > 45) {
Yii::app()->setFlashMessage(sprintf(gT("The name is too long.")), 'error');
Yii::app()->getController()->redirect(array('themeOptions/index'));
Yii::app()->end();
}
}
/**
* @return array relational rules.
*/
public function relations()
{
return array(
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'name' => 'Name',
'folder' => 'Folder',
'title' => 'Title',
'creation_date' => 'Creation Date',
'author' => 'Author',
'author_email' => 'Author Email',
'author_url' => 'Author Url',
'copyright' => 'Copyright',
'license' => 'License',
'version' => 'Version',
'api_version' => 'Api Version',
'view_folder' => 'View Folder',
'files_folder' => 'Files Folder',
'description' => 'Description',
'last_update' => 'Last Update',
'owner_id' => 'Owner',
'extends' => 'Extends Templates Name',
);
}
/**
* Returns this table's primary key
*
* @access public
* @return string
*/
public function primaryKey()
{
return 'name';
}
/**
* Filter the template name : test if template exists
*
* @param string $sTemplateName
* @return string existing $sTemplateName
* @throws Exception
*/
public static function templateNameFilter($sTemplateName)
{
$sTemplateName = sanitize_filename($sTemplateName, false, false, false, true);
// If the names has already been filtered, we skip the process
if (!empty(self::$aNamesFiltered[$sTemplateName])) {
return self::$aNamesFiltered[$sTemplateName];
}
$sRequestedTemplate = $sTemplateName;
$sDefaultTemplate = App()->getConfig('defaulttheme');
/* Validate if template is OK in user dir, DIRECTORY_SEPARATOR not needed "/" is OK */
$oTemplate = self::model()->findByPk($sTemplateName);
if (
!empty($oTemplate)
&& $oTemplate->checkTemplate()
&& (self::checkTemplateXML($oTemplate))
) {
self::$aNamesFiltered[$sTemplateName] = $sTemplateName;
return self::$aNamesFiltered[$sTemplateName];
}
/* Then try with the global default template */
if ($sTemplateName != $sDefaultTemplate) {
return self::templateNameFilter($sDefaultTemplate);
}
/* If we're here, then the default survey theme is not installed and must be changed */
$aTemplateList = self::model()->search()->getData();
$i = 0;
while ($sTemplateName == $sRequestedTemplate) {
if (!empty($aTemplateList[$i])) {
$sTemplateName = $aTemplateList[$i]->name;
} else {
throw new Exception('Could not find a working installed template');
}
$i++;
}
if (!empty($sTemplateName)) {
SettingGlobal::setSetting('defaulttheme', $sTemplateName);
$sDefaultTemplate = App()->getConfig('defaulttheme');
if (method_exists(Yii::app(), 'setFlashMessage')) {
Yii::app()->setFlashMessage(sprintf(gT("Default survey theme %s is not installed. Now %s is the new default survey theme"), $sRequestedTemplate, $sTemplateName), 'error');
}
self::$aNamesFiltered[$sTemplateName] = $sTemplateName;
return $sTemplateName;
} else {
throw new Exception('No survey theme installed !!!!');
}
}
/**
* @return boolean
* @throws Exception if extended template is not installed.
*/
public function checkTemplate()
{
// Check that extended template is installed.
$this->checkTemplateExtends();
// A template should not extend it self.
$this->checkExtendsItSelf();
return true;
}
/**
* Throws exception if any of the extended templates are not installed; otherwise
* returns true.
* @return boolean
* @throws Exception if extended template is not installed.
*/
public function checkTemplateExtends()
{
/**
* TODO: the following code needs to be rewritten, currently the only thing it does is return true, that why it is commented out
*/
return true;
// if (!empty($this->extends)) {
// $oRTemplate = self::model()->findByPk($this->extends);
// if (empty($oRTemplate)) {
// // Why? it blocks the user at login screen....
// // It should return false and show a nice warning message.
//
// /*throw new Exception(
// sprintf(
// 'Extended template "%s" is not installed.',
// $this->extends
// )
// );*/
// }
// }
// return true;
}
/**
* @return boolean
* @throws Exception if name equals extends.
*/
public function checkExtendsItSelf()
{
if ($this->name == $this->extends) {
throw new Exception(
sprintf(
'Error: The template %s extends it self',
$this->name
)
);
}
return true;
}
/**
* Check if a given Template has a valid XML File
*
* @param Template $template The template model
* @return boolean
* @throws CDbException
*/
public static function checkTemplateXML($template)
{
// Core templates should never be checked for validity
// TODO: we can not trust the filestate and need to be
// able to check the theme type (core or custom) from the database, this should replace the call to getTemplatesData()
$templates = array_column(LsDefaultDataSets::getTemplatesData(), 'name');
if (in_array($template->name, $templates, true)) {
return true;
}
// check if the configuration can be found
$userThemePath = App()->getConfig("userthemerootdir") . DIRECTORY_SEPARATOR . $template->folder . DIRECTORY_SEPARATOR . 'config.xml';
$standardThemePath = App()->getConfig("standardthemerootdir") . DIRECTORY_SEPARATOR . $template->folder . DIRECTORY_SEPARATOR . 'config.xml';
if (is_file($userThemePath)) {
$currentThemePath = $userThemePath;
} elseif (is_file($standardThemePath)) {
$currentThemePath = $standardThemePath;
} else {
return false;
}
// check compatability with current limesurvey version
if (!TemplateConfig::validateTheme($template->name, $currentThemePath)) {
return false;
}
// all checks succeeded, continue loading the theme
return true;
}
/**
* @param string $sTemplateName
* @return bool
*/
public static function checkIfTemplateExists($sTemplateName)
{
// isset is faster, and we need a value, no need var here
return isset(self::getTemplateList()[$sTemplateName]);
}
/**
* Get the template path for any template : test if template exists
*
* @param string $sTemplateName
* @return string template path
* @throws Exception
*/
public static function getTemplatePath($sTemplateName = "")
{
$sTemplateName = self::templateNameFilter($sTemplateName);
// Make sure template name is valid
if (!self::checkIfTemplateExists($sTemplateName)) {
throw new \CException("Invalid {$sTemplateName} template directory");
}
static $aTemplatePath = array();
if (isset($aTemplatePath[$sTemplateName])) {
return $aTemplatePath[$sTemplateName];
}
$oTemplate = self::model()->findByPk($sTemplateName);
if (empty($oTemplate)) {
throw new \CException("Survey theme {$sTemplateName} not found.", 1);
}
Yii::import('application.helpers.SurveyThemeHelper');
if (SurveyThemeHelper::isStandardTemplate($sTemplateName)) {
return $aTemplatePath[$sTemplateName] = Yii::app()->getConfig("standardthemerootdir") . DIRECTORY_SEPARATOR . $oTemplate->folder;
} else {
return $aTemplatePath[$sTemplateName] = Yii::app()->getConfig("userthemerootdir") . DIRECTORY_SEPARATOR . $oTemplate->folder;
}
}
/**
* This method construct a template object, having all the needed configuration datas.
* It checks if the required template is a core one or a user one.
* If it's a user template, it will check if it's an old 2.0x template to provide default configuration values corresponding to the old template system
* If it's not an old template, it will check if it has a configuration file to load its datas.
* If it's not the case (template probably doesn't exist), it will load the default template configuration
* TODO : more tests should be done, with a call to private function _is_valid_template(), testing not only if it has a config.xml, but also id this file is correct, if the files refered in css exist, etc.
*
* @param string $sTemplateName the name of the template to load. The string come from the template selector in survey settings
* @param integer $iSurveyId the id of the survey.
* @param integer $iSurveyId the id of the survey.
* @param boolean $bForceXML the id of the survey.
* @return TemplateConfiguration|TemplateManifest
*/
public static function getTemplateConfiguration($sTemplateName = null, $iSurveyId = null, $iSurveyGroupId = null, $bForceXML = false, $abstractInstance = false)
{
// First we try to get a configuration row from DB
if (!$bForceXML) {
// The name need to be filtred only for DB version. From TemplateEditor, the template is not installed.
$sTemplateName = (empty($sTemplateName)) ? null : self::templateNameFilter($sTemplateName);
$oTemplateConfigurationModel = TemplateConfiguration::getInstance($sTemplateName, $iSurveyGroupId, $iSurveyId, $abstractInstance);
}
// If no row found, or if the template folder for this configuration row doesn't exist we load the XML config (which will load the default XML)
if ($bForceXML || !is_a($oTemplateConfigurationModel, 'TemplateConfiguration') || !$oTemplateConfigurationModel->checkTemplate()) {
$oTemplateConfigurationModel = new TemplateManifest(null);
$oTemplateConfigurationModel->setBasics($sTemplateName, $iSurveyId);
}
//$oTemplateConfigurationModel->prepareTemplateRendering($sTemplateName, $iSurveyId);
return $oTemplateConfigurationModel;
}
/**
* Return the list of ALL files present in the file directory
*
* @param string $filesDir
* @return array
*/
public static function getOtherFiles($filesDir)
{
$otherFiles = array();
if (file_exists($filesDir) && $handle = opendir($filesDir)) {
while (false !== ($file = readdir($handle))) {
// The file '..' can mess with open_basedir permissions.
if ($file == '..' || $file == '.') {
continue;
}
if (!is_dir($file)) {
$otherFiles[] = array("name" => $file);
}
}
closedir($handle);
}
return $otherFiles;
}
/**
* This function returns the complete URL path to a given template name
*
* @param string $sTemplateName
* @return string template url
*/
public static function getTemplateURL($sTemplateName = "")
{
$sTemplateName = self::templateNameFilter($sTemplateName);
// Make sure template name is valid
if (!self::checkIfTemplateExists($sTemplateName)) {
throw new \CException("Invalid {$sTemplateName} template directory");
}
static $aTemplateUrl = array();
if (isset($aTemplateUrl[$sTemplateName])) {
return $aTemplateUrl[$sTemplateName];
}
$oTemplate = self::model()->findByPk($sTemplateName);
if (is_object($oTemplate)) {
Yii::import('application.helpers.SurveyThemeHelper');
if (SurveyThemeHelper::isStandardTemplate($sTemplateName)) {
return $aTemplateUrl[$sTemplateName] = Yii::app()->getConfig("standardthemerooturl") . '/' . $oTemplate->folder . '/';
} else {
return $aTemplateUrl[$sTemplateName] = Yii::app()->getConfig("userthemerooturl") . '/' . $oTemplate->folder . '/';
}
} else {
return '';
}
}
/**
* This function returns the complete URL path to a given template name
*
* @param string $sTemplateName
* @return string template url
*/
public static function getTemplatesFileFolder($sTemplateName = "")
{
static $aTemplatesFileFolder = array();
if (isset($aTemplatesFileFolder[$sTemplateName])) {
return $aTemplatesFileFolder[$sTemplateName];
}
$oTemplate = self::model()->findByPk($sTemplateName);
if (is_object($oTemplate)) {
return $aTemplatesFileFolder[$sTemplateName] = $oTemplate->files_folder;
} else {
return '';
}
}
/**
* Returns an array of all available template names - check if template exist
* key is template name, value is template folder
* @return string|array
*/
public static function getTemplateList()
{
static $aTemplateList = null;
if (!is_null($aTemplateList)) {
return $aTemplateList;
}
$aTemplateList = [];
/* Get the template name by TemplateConfiguration and fiolder by template , no need other data */
$criteria = new CDBCriteria();
$criteria->select = 'template_name';
$criteria->condition = 'sid IS NULL AND gsid IS NULL AND template.folder IS NOT NULL';
$oTemplateList = TemplateConfiguration::model()->with(array(
'template' => ['select' => 'id, folder'],
))->findAll($criteria);
$aTemplateInStandard = SurveyThemeHelper::getTemplateInStandard();
$aTemplateInUpload = SurveyThemeHelper::getTemplateInUpload();
foreach ($oTemplateList as $oTemplate) {
if (isset($aTemplateInStandard[$oTemplate->template->folder])) {
$aTemplateList[$oTemplate->template_name] = $aTemplateInStandard[$oTemplate->template->folder];
} elseif (isset($aTemplateInUpload[$oTemplate->template->folder])) {
$aTemplateList[$oTemplate->template_name] = $aTemplateInUpload[$oTemplate->template->folder];
}
}
return $aTemplateList;
}
/**
* Return the array of existing and installed template with the preview images
* @deprecated 2024-04-25 use directly Template::getTemplateList
* @return array[]
*/
public static function getTemplateListWithPreviews()
{
$criteria = new CDBCriteria();
$criteria->select = 'template_name';
$criteria->condition = 'sid IS NULL AND gsid IS NULL';
$criteria->addInCondition('template_name', array_keys(self::getTemplateList()));
$oTemplateList = TemplateConfiguration::model()->with(array(
'template' => ['select' => 'id, name'],
))->findAll($criteria);
$aTemplateList = array();
foreach ($oTemplateList as $oTemplate) {
$aTemplateList[$oTemplate->template_name]['preview'] = $oTemplate->preview;
}
return $aTemplateList;
}
/**
* isStandardTemplate returns true if a template is a standard template
* This function does not check if a template actually exists
*
* @param mixed $sTemplateName template name to look for
* @return bool True if standard template, otherwise false
* @deprecated Use SurveyThemeHelper::getStandardTemplateList() instead.
*/
public static function isStandardTemplate($sTemplateName)
{
// Refactored into SurveyThemeHelper. Replaced the code here
// by a call to the helper to avoid code duplication while keeping
// backwards compatibility.
Yii::import('application.helpers.SurveyThemeHelper');
return SurveyThemeHelper::isStandardTemplate($sTemplateName);
}
/**
* Get instance of template object.
* Will instantiate the template object first time it is called.
*
* NOTE 1: This function will call prepareTemplateRendering that create/update all the packages needed to render the template, which imply to do the same for all mother templates
* NOTE 2: So if you just want to access the TemplateConfiguration AR Object, you don't need to use this one. Call it only before rendering anything related to the template.
* NOTE 3: If you need to get the related configuration to this template, rather use: getTemplateConfiguration()
* NOTE 4: If you want the lastest generated theme, just call Template::getLastInstance()
*
* @param string $sTemplateName
* @param int|string $iSurveyId
* @param int|string $iSurveyGroupId
* @param boolean $bForceXML
* @param boolean $last if you want to get the last instace without providing template name or sid
* @return self
*/
public static function getInstance($sTemplateName = null, $iSurveyId = null, $iSurveyGroupId = null, $bForceXML = null, $abstractInstance = false, $last = false)
{
if ($bForceXML === null) {
// Template developer could prefer to work with XML rather than DB as a first step, for quick and easy changes
$bForceXML = (App()->getConfig('force_xmlsettings_for_survey_rendering')) ? true : false;
}
// The error page from default template can be called when no survey found with a specific ID.
if ($sTemplateName === null && $iSurveyId === null && $last === false) {
$sTemplateName = App()->getConfig('defaulttheme');
}
// TODO: this probably not use any more. Check and remove it.
if ($abstractInstance === true) {
return self::getTemplateConfiguration($sTemplateName, $iSurveyId, $iSurveyGroupId, $bForceXML, true);
}
if (empty(self::$instance) || ! self::isCorrectInstance($sTemplateName)) {
self::$instance = self::getTemplateConfiguration($sTemplateName, $iSurveyId, $iSurveyGroupId, $bForceXML);
self::$instance->prepareTemplateRendering($sTemplateName, $iSurveyId);
}
return self::getLastInstance(false);
}
/**
* Return last instance if it exists, else generate it or throw an exception depending on $bAutoGenerate.
* @param boolean $bAutoGenerate : should the function try to generate an instance if it doesn't exist?
* @return self
*/
public static function getLastInstance($bAutoGenerate = true)
{
if (empty(self::$instance)) {
if ($bAutoGenerate) {
self::getInstance();
} else {
throw new \Exception("No Survey theme was generated", 1);
}
}
return self::$instance;
}
/**
* Check if the current instance is the correct one. Could be more complex in the future
* @param string $sTemplateName
* @return boolean
*/
public static function isCorrectInstance($sTemplateName = null)
{
return ( $sTemplateName == null || self::$instance->sTemplateName == $sTemplateName);
}
/**
* Sets self::$instance to null;
* Needed for unit test.
*/
public static function resetInstance()
{
self::$instance = null;
}
/**
* Alias function for resetAssetVersion()
* Don't delete this one to maintain updgrade compatibility
* @return void
*/
public function forceAssets()
{
$this->resetAssetVersion();
}
/**
* Reset assets for this template
* Using DB only
* @return void
*/
public function resetAssetVersion()
{
AssetVersion::incrementAssetVersion(self::getTemplatePath($this->name));
}
/**
* Delete asset related to this template
* Using DB only
* @return integer (0|1)
*/
public function deleteAssetVersion()
{
return AssetVersion::deleteAssetVersion(self::getTemplatePath($this->name));
}
/**
* Return the standard template list
* @return string[]
* @throws Exception
* @deprecated Use SurveyThemeHelper::getStandardTemplateList() instead.
*/
public static function getStandardTemplateList()
{
// Refactored into SurveyThemeHelper. Replaced the code here
// by a call to the helper to avoid code duplication while keeping
// backwards compatibility.
Yii::import('application.helpers.SurveyThemeHelper');
return SurveyThemeHelper::getStandardTemplateList();
}
public static function hasInheritance($sTemplateName)
{
return self::model()->countByAttributes(array('extends' => $sTemplateName));
}
public static function getAllTemplatesDirectories()
{
if (empty(self::$aAllTemplatesDir)) {
Yii::import('application.helpers.SurveyThemeHelper');
$aTemplatesInUpload = SurveyThemeHelper::getTemplateInUpload();
$aTemplatesInCore = SurveyThemeHelper::getTemplateInStandard();
self::$aAllTemplatesDir = array_merge($aTemplatesInUpload, $aTemplatesInCore);
}
return self::$aAllTemplatesDir;
}
/**
* @deprecated Use SurveyThemeHelper::getTemplateInUpload() instead.
*/
public static function getTemplateInUpload()
{
// Refactored into SurveyThemeHelper. Replaced the code here
// by a call to the helper to avoid code duplication while keeping
// backwards compatibility.
Yii::import('application.helpers.SurveyThemeHelper');
return SurveyThemeHelper::getTemplateInUpload();
}
/**
* @deprecated Use SurveyThemeHelper::getTemplateInStandard() instead.
*/
public static function getTemplateInStandard()
{
// Refactored into SurveyThemeHelper. Replaced the code here
// by a call to the helper to avoid code duplication while keeping
// backwards compatibility.
Yii::import('application.helpers.SurveyThemeHelper');
return SurveyThemeHelper::getTemplateInStandard();
}
/**
* @deprecated Use SurveyThemeHelper::getTemplateInFolder() instead.
*/
public static function getTemplateInFolder($sFolder)
{
// Refactored into SurveyThemeHelper. Replaced the code here
// by a call to the helper to avoid code duplication while keeping
// backwards compatibility.
Yii::import('application.helpers.SurveyThemeHelper');
return SurveyThemeHelper::getTemplateInFolder($sFolder);
}
/**
* Change the template name inside DB and the manifest (called from template editor)
* NOTE: all tests (like template exist, etc) are done from template controller.
*
* @param string $sNewName The newname of the template
*/
public function renameTo($sNewName)
{
Yii::import('application.helpers.sanitize_helper', true);
$this->deleteAssetVersion();
Survey::model()->updateAll(array('template' => $sNewName), "template = :oldname", array(':oldname' => $this->name));
SurveysGroupsettings::model()->updateAll(['template' => $sNewName], "template = :oldname", [':oldname' => $this->name]);
Template::model()->updateAll(array('name' => $sNewName, 'folder' => $sNewName), "name = :oldname", array(':oldname' => $this->name));
Template::model()->updateAll(array('extends' => $sNewName), "extends = :oldname", array(':oldname' => $this->name));
TemplateConfiguration::rename($this->name, $sNewName);
TemplateManifest::rename($this->name, $sNewName);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* @return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// @todo Please modify the following code to remove attributes that should not be searched.
$criteria = new LSDbCriteria();
$criteria->compare('name', $this->name, true);
$criteria->compare('folder', $this->folder, true);
$criteria->compare('title', $this->title, true);
$criteria->compare('creation_date', $this->creation_date, true);
$criteria->compare('author', $this->author, true);
$criteria->compare('author_email', $this->author_email, true);
$criteria->compare('author_url', $this->author_url, true);
$criteria->compare('copyright', $this->copyright, true);
$criteria->compare('license', $this->license, true);
$criteria->compare('version', $this->version, true);
$criteria->compare('api_version', $this->api_version, true);
$criteria->compare('view_folder', $this->view_folder, true);
$criteria->compare('files_folder', $this->files_folder, true);
$criteria->compare('description', $this->description, true);
$criteria->compare('last_update', $this->last_update, true);
$criteria->compare('owner_id', $this->owner_id);
$criteria->compare('extends', $this->extends, true);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
/**
* Retrieves a list of deprecated templates (the templates in upload/templates/)
*/
public static function getDeprecatedTemplates()
{
$usertemplaterootdir = App()->getConfig("uploaddir") . DIRECTORY_SEPARATOR . "templates";
$aTemplateList = array();
if ((is_dir($usertemplaterootdir)) && $usertemplaterootdir && $handle = opendir($usertemplaterootdir)) {
while (false !== ($file = readdir($handle))) {
if (!is_file("$usertemplaterootdir/$file") && $file != "." && $file != ".." && $file != ".svn") {
$aTemplateList[$file]['directory'] = $usertemplaterootdir . DIRECTORY_SEPARATOR . $file;
$aTemplateList[$file]['name'] = $file;
}
}
closedir($handle);
}
ksort($aTemplateList);
return $aTemplateList;
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* @param string $className active record class name.
* @return Template the static model class
*/
public static function model($className = __CLASS__)
{
/** @var self $model */
$model = parent::model($className);
return $model;
}
}