diff --git a/code/admin/UserTemplateAdmin.php b/code/admin/UserTemplateAdmin.php index e30e2c0..a65dba7 100644 --- a/code/admin/UserTemplateAdmin.php +++ b/code/admin/UserTemplateAdmin.php @@ -6,9 +6,9 @@ * @author marcus@silverstripe.com.au * @license BSD License http://silverstripe.org/bsd-license/ */ -class UserTemplateAdmin extends ModelAdmin { - public static $menu_title = 'Templates'; - public static $url_segment = 'templates'; - public static $managed_models = array('UserTemplate'); - +class UserTemplateAdmin extends ModelAdmin +{ + public static $menu_title = 'Templates'; + public static $url_segment = 'templates'; + public static $managed_models = array('UserTemplate'); } diff --git a/code/dataobjects/UserTemplate.php b/code/dataobjects/UserTemplate.php index f48fafc..ba4ad3b 100644 --- a/code/dataobjects/UserTemplate.php +++ b/code/dataobjects/UserTemplate.php @@ -6,181 +6,190 @@ * @author marcus@silverstripe.com.au * @license BSD License http://silverstripe.org/bsd-license/ */ -class UserTemplate extends DataObject { - public static $db = array( - 'Title' => 'Varchar', - 'Description' => 'Varchar', - 'Use' => "Enum('Layout,Master')", - 'Content' => 'Text', - 'ContentFile' => 'Varchar(132)', - 'StrictActions' => 'Boolean', - 'ActionTemplates' => 'MultiValueField', - ); +class UserTemplate extends DataObject +{ + public static $db = array( + 'Title' => 'Varchar', + 'Description' => 'Varchar', + 'Use' => "Enum('Layout,Master')", + 'Content' => 'Text', + 'ContentFile' => 'Varchar(132)', + 'StrictActions' => 'Boolean', + 'ActionTemplates' => 'MultiValueField', + ); - public static $many_many = array( - 'CustomCSSFiles' => 'File', - 'CustomJSFiles' => 'File' - ); - - - /** - * folder for custom javascript files - * @var string - **/ - protected static $js_folder = 'custom-theme/javascript'; + public static $many_many = array( + 'CustomCSSFiles' => 'File', + 'CustomJSFiles' => 'File' + ); + + + /** + * folder for custom javascript files + * @var string + **/ + protected static $js_folder = 'custom-theme/javascript'; - /** - * folder for custom css files - * @var string - **/ - protected static $css_folder = 'custom-theme/css'; + /** + * folder for custom css files + * @var string + **/ + protected static $css_folder = 'custom-theme/css'; - public function getCMSFields() { - $fields = parent::getCMSFields(); - - $cssFiles = new UploadField('CustomCSSFiles',_t('UserTemplatesExtension.CustomCSSFiles',"Custom CSS Files")); - $jsFiles = new UploadField('CustomJSFiles',_t('UserTemplatesExtension.CustomJSFiles',"Custom JS Files")); - $cssFiles->setFolderName(self::$css_folder); - $jsFiles->setFolderName(self::$js_folder); + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + $cssFiles = new UploadField('CustomCSSFiles', _t('UserTemplatesExtension.CustomCSSFiles', "Custom CSS Files")); + $jsFiles = new UploadField('CustomJSFiles', _t('UserTemplatesExtension.CustomJSFiles', "Custom JS Files")); + $cssFiles->setFolderName(self::$css_folder); + $jsFiles->setFolderName(self::$js_folder); - $fields->removeByName('CustomCSSFiles'); - $fields->removeByName('CustomJSFiles'); + $fields->removeByName('CustomCSSFiles'); + $fields->removeByName('CustomJSFiles'); - $templates = $this->fileBasedTemplates(); - if (count($templates)) { - $fields->addFieldToTab('Root.Main', $dd = new DropdownField('ContentFile', _t('UserTemplatesExtension.CONTENT_FILE', 'File containing template'), $templates)); - $dd->setRightTitle('If selected, any Content set above will be ignored'); - } else { - $fields->removeByName('ContentFile'); - } - - $fields->push($strict = CheckboxField::create('StrictActions', _t('UserTemplates.STRICT_ACTIONS', 'Require actions to be explicitly overridden'))); - $text = <<fileBasedTemplates(); + if (count($templates)) { + $fields->addFieldToTab('Root.Main', $dd = new DropdownField('ContentFile', _t('UserTemplatesExtension.CONTENT_FILE', 'File containing template'), $templates)); + $dd->setRightTitle('If selected, any Content set above will be ignored'); + } else { + $fields->removeByName('ContentFile'); + } + + $fields->push($strict = CheckboxField::create('StrictActions', _t('UserTemplates.STRICT_ACTIONS', 'Require actions to be explicitly overridden'))); + $text = <<setRightTitle(_t('UserTemplates.STRICT_HELP', $text)); - - $templates = DataList::create('UserTemplate')->filter(array('ID:not' => $this->ID)); - if ($templates->count()) { - $templates = $templates->map(); - $fields->addFieldToTab('Root.Main', $kv = new KeyValueField('ActionTemplates', _t('UserTemplates.ACTION_TEMPLATES', 'Action specific templates'), array(), $templates)); - $kv->setRightTitle(_t('UserTemplates.ACTION_TEMPLATES_HELP', 'Specify an action name and select another user defined template to handle a specific action. Only used for Layout templates')); - } - - - $fields->addFieldToTab('Root.Main', $cssFiles); - $fields->addFieldToTab('Root.Main', $jsFiles); + $strict->setRightTitle(_t('UserTemplates.STRICT_HELP', $text)); + + $templates = DataList::create('UserTemplate')->filter(array('ID:not' => $this->ID)); + if ($templates->count()) { + $templates = $templates->map(); + $fields->addFieldToTab('Root.Main', $kv = new KeyValueField('ActionTemplates', _t('UserTemplates.ACTION_TEMPLATES', 'Action specific templates'), array(), $templates)); + $kv->setRightTitle(_t('UserTemplates.ACTION_TEMPLATES_HELP', 'Specify an action name and select another user defined template to handle a specific action. Only used for Layout templates')); + } + + + $fields->addFieldToTab('Root.Main', $cssFiles); + $fields->addFieldToTab('Root.Main', $jsFiles); - return $fields; - } + return $fields; + } - protected function fileBasedTemplates() { - $templates = array('' => 'None'); - foreach (glob(Director::baseFolder() . '/' . THEMES_DIR .'/*', GLOB_ONLYDIR) as $theme) { - $themeName = ucfirst(basename($theme)); - if (is_dir($theme .'/user-templates')) { - foreach (glob($theme.'/user-templates/*.ss') as $templateFile) { - $templateFile = str_replace(Director::baseFolder() . '/', '', $templateFile); - $templates[$templateFile] = $themeName . ' - ' . basename($templateFile); - } - } - } - - return $templates; - } - - public function onBeforeWrite() { - parent::onBeforeWrite(); - $this->Title = FileNameFilter::create()->filter($this->Title); - - if (strlen($this->ContentFile)) { - $templates = $this->fileBasedTemplates(); - if (!isset($templates[$this->ContentFile])) { - $this->ContentFile = ''; - } - } - } + protected function fileBasedTemplates() + { + $templates = array('' => 'None'); + foreach (glob(Director::baseFolder() . '/' . THEMES_DIR .'/*', GLOB_ONLYDIR) as $theme) { + $themeName = ucfirst(basename($theme)); + if (is_dir($theme .'/user-templates')) { + foreach (glob($theme.'/user-templates/*.ss') as $templateFile) { + $templateFile = str_replace(Director::baseFolder() . '/', '', $templateFile); + $templates[$templateFile] = $themeName . ' - ' . basename($templateFile); + } + } + } + + return $templates; + } + + public function onBeforeWrite() + { + parent::onBeforeWrite(); + $this->Title = FileNameFilter::create()->filter($this->Title); + + if (strlen($this->ContentFile)) { + $templates = $this->fileBasedTemplates(); + if (!isset($templates[$this->ContentFile])) { + $this->ContentFile = ''; + } + } + } - public function onAfterWrite() { - if (strlen($this->Content)) { - $this->generateCacheFile(); - } - } + public function onAfterWrite() + { + if (strlen($this->Content)) { + $this->generateCacheFile(); + } + } - protected function generateCacheFile() { - $file = $this->getCacheFilename(); - file_put_contents($file, $this->Content); - } - - /** - * Return an override template for a specific action if given - * - * @param string $action - */ - public function getActionOverride($action) { - if ($this->ActionTemplates) { - $actions = $this->ActionTemplates->getValues(); - if ($actions && isset($actions[$action])) { - return DataList::create('UserTemplate')->byID($actions[$action]); - } - } - } - - /** - * Get a filename that represents the - * - * @return string - */ - public function getTemplateFile() { - if (strlen($this->ContentFile)) { - $templateFile = Director::baseFolder() . '/' . $this->ContentFile; - if (file_exists($templateFile)) { - return $templateFile; - } - } + protected function generateCacheFile() + { + $file = $this->getCacheFilename(); + file_put_contents($file, $this->Content); + } + + /** + * Return an override template for a specific action if given + * + * @param string $action + */ + public function getActionOverride($action) + { + if ($this->ActionTemplates) { + $actions = $this->ActionTemplates->getValues(); + if ($actions && isset($actions[$action])) { + return DataList::create('UserTemplate')->byID($actions[$action]); + } + } + } + + /** + * Get a filename that represents the + * + * @return string + */ + public function getTemplateFile() + { + if (strlen($this->ContentFile)) { + $templateFile = Director::baseFolder() . '/' . $this->ContentFile; + if (file_exists($templateFile)) { + return $templateFile; + } + } - $file = $this->getCacheFilename(); - if (!@filesize($file)) { - clearstatcache(); - $this->generateCacheFile(); - return $file; - } + $file = $this->getCacheFilename(); + if (!@filesize($file)) { + clearstatcache(); + $this->generateCacheFile(); + return $file; + } - return $file; - } - - /** - * Get the name of the cache file - * - * @return string - */ - protected function getCacheFilename() { - $dir = BASE_PATH . '/usertemplates/template-cache/' . $this->Use . '/'; - Filesystem::makeFolder($dir); - $file = $dir . '/' . $this->Title . '.ss'; - if (!file_exists($file)) { - touch($file); - chmod($file, 0664); - } - return $file; - } - - public function includeRequirements() { - $obj = $this->CustomCSSFiles(); - if ($obj) { - foreach ($obj as $file) { - Requirements::css($file->Filename); - } - } - - $obj = $this->CustomJSFiles(); - if ($obj) { - foreach ($obj as $file) { - Requirements::javascript($file->Filename); - } - } - - } + return $file; + } + + /** + * Get the name of the cache file + * + * @return string + */ + protected function getCacheFilename() + { + $dir = BASE_PATH . '/usertemplates/template-cache/' . $this->Use . '/'; + Filesystem::makeFolder($dir); + $file = $dir . '/' . $this->Title . '.ss'; + if (!file_exists($file)) { + touch($file); + chmod($file, 0664); + } + return $file; + } + + public function includeRequirements() + { + $obj = $this->CustomCSSFiles(); + if ($obj) { + foreach ($obj as $file) { + Requirements::css($file->Filename); + } + } + + $obj = $this->CustomJSFiles(); + if ($obj) { + foreach ($obj as $file) { + Requirements::javascript($file->Filename); + } + } + } } diff --git a/code/extensions/UserTemplatesExtension.php b/code/extensions/UserTemplatesExtension.php index 5c92606..aabbae2 100644 --- a/code/extensions/UserTemplatesExtension.php +++ b/code/extensions/UserTemplatesExtension.php @@ -1,91 +1,95 @@ 'Boolean', - ); - - public static $has_one = array( - 'MasterTemplate' => 'UserTemplate', - 'LayoutTemplate' => 'UserTemplate', - ); - - public static $defaults = array( - 'InheritTemplateSettings' => 1 - ); +class UserTemplatesExtension extends DataExtension +{ + + public static $db = array( + 'InheritTemplateSettings' => 'Boolean', + ); + + public static $has_one = array( + 'MasterTemplate' => 'UserTemplate', + 'LayoutTemplate' => 'UserTemplate', + ); + + public static $defaults = array( + 'InheritTemplateSettings' => 1 + ); - public function updateSettingsFields(FieldList $fields) { - $layouts = DataList::create('UserTemplate')->filter(array('Use' => 'Layout')); - $masters = DataList::create('UserTemplate')->filter(array('Use' => 'Master')); + public function updateSettingsFields(FieldList $fields) + { + $layouts = DataList::create('UserTemplate')->filter(array('Use' => 'Layout')); + $masters = DataList::create('UserTemplate')->filter(array('Use' => 'Master')); - $fields->addFieldToTab('Root.Theme', DropdownField::create('MasterTemplateID', 'Master Template', $masters->map(), '', null)->setEmptyString('None')); - $fields->addFieldToTab('Root.Theme', DropdownField::create('LayoutTemplateID', 'Layout Template', $layouts->map(), '', null)->setEmptyString('None')); - $fields->addFieldToTab('Root.Theme', CheckboxField::create('InheritTemplateSettings', 'Inherit Settings')); - - $effectiveMaster = $this->effectiveTemplate(); - $effectiveLayout = $this->effectiveTemplate('Layout'); - - if($effectiveMaster){ - $fields->addFieldToTab('Root.Theme', ReadonlyField::create('EffectiveMaster', 'Effective master template', $effectiveMaster->Title)); - } - - if($effectiveLayout){ - $fields->addFieldToTab('Root.Theme', ReadonlyField::create('EffectiveLayout', 'Effective layout template', $effectiveLayout->Title)); - } - - return $fields; - } - - /** - * - * @param string $type - * Whether to get a master or layout template - * @param string $action - * If there's a specific action involved for the template - * @return type - */ - public function effectiveTemplate($type = 'Master', $action = null) { - $name = $type . 'Template'; - $id = $name . 'ID'; - if ($this->owner->$id) { - $template = $this->owner->getComponent($name); - if ($action && $action != 'index') { - // see if there's an override for this specific action - $override = $template->getActionOverride($action); - - // if the template is strict, then we MUST have the action defined - // otherwise we need to return null - so we set $template IF this is the case, - // regardless of whether we found an override, OR if the override was set - if ($template->StrictActions || $override) { - $template = $override; - } - } - return $template; - } - - if ($this->owner->InheritTemplateSettings && $this->owner->ParentID) { - return $this->owner->Parent()->effectiveTemplate($type, $action); - } - } + $fields->addFieldToTab('Root.Theme', DropdownField::create('MasterTemplateID', 'Master Template', $masters->map(), '', null)->setEmptyString('None')); + $fields->addFieldToTab('Root.Theme', DropdownField::create('LayoutTemplateID', 'Layout Template', $layouts->map(), '', null)->setEmptyString('None')); + $fields->addFieldToTab('Root.Theme', CheckboxField::create('InheritTemplateSettings', 'Inherit Settings')); + + $effectiveMaster = $this->effectiveTemplate(); + $effectiveLayout = $this->effectiveTemplate('Layout'); + + if ($effectiveMaster) { + $fields->addFieldToTab('Root.Theme', ReadonlyField::create('EffectiveMaster', 'Effective master template', $effectiveMaster->Title)); + } + + if ($effectiveLayout) { + $fields->addFieldToTab('Root.Theme', ReadonlyField::create('EffectiveLayout', 'Effective layout template', $effectiveLayout->Title)); + } + + return $fields; + } + + /** + * + * @param string $type + * Whether to get a master or layout template + * @param string $action + * If there's a specific action involved for the template + * @return type + */ + public function effectiveTemplate($type = 'Master', $action = null) + { + $name = $type . 'Template'; + $id = $name . 'ID'; + if ($this->owner->$id) { + $template = $this->owner->getComponent($name); + if ($action && $action != 'index') { + // see if there's an override for this specific action + $override = $template->getActionOverride($action); + + // if the template is strict, then we MUST have the action defined + // otherwise we need to return null - so we set $template IF this is the case, + // regardless of whether we found an override, OR if the override was set + if ($template->StrictActions || $override) { + $template = $override; + } + } + return $template; + } + if ($this->owner->InheritTemplateSettings && $this->owner->ParentID) { + return $this->owner->Parent()->effectiveTemplate($type, $action); + } + } } -class UserTemplatesControllerExtension extends Extension { - - public function updateViewer($action, $viewer) { - $master = $this->owner->data()->effectiveTemplate('Master'); - if ($master && $master->ID) { - // set the main template - $master->includeRequirements(); - $viewer->setTemplateFile('main', $master->getTemplateFile()); - } +class UserTemplatesControllerExtension extends Extension +{ + + public function updateViewer($action, $viewer) + { + $master = $this->owner->data()->effectiveTemplate('Master'); + if ($master && $master->ID) { + // set the main template + $master->includeRequirements(); + $viewer->setTemplateFile('main', $master->getTemplateFile()); + } - $layout = $this->owner->data()->effectiveTemplate('Layout', $action); + $layout = $this->owner->data()->effectiveTemplate('Layout', $action); - if ($layout && $layout->ID) { - $layout->includeRequirements(); - $viewer->setTemplateFile('Layout', $layout->getTemplateFile()); - } - } -} \ No newline at end of file + if ($layout && $layout->ID) { + $layout->includeRequirements(); + $viewer->setTemplateFile('Layout', $layout->getTemplateFile()); + } + } +} diff --git a/code/extensions/UserTemplatesSSViewer.php b/code/extensions/UserTemplatesSSViewer.php index a042e4d..db4d463 100644 --- a/code/extensions/UserTemplatesSSViewer.php +++ b/code/extensions/UserTemplatesSSViewer.php @@ -1,35 +1,35 @@ chosenTemplates['main'] = $templateList; - } else { - $this->chosenTemplates = SS_TemplateLoader::instance()->findTemplates( - $templateList, self::current_theme() - ); - //Debug::show($this->chosenTemplates); - } + public function __construct($templateList) + { + // flush template manifest cache if requested + if (isset($_GET['flush']) && $_GET['flush'] == 'all') { + if (Director::isDev() || Director::is_cli() || Permission::check('ADMIN')) { + self::flush_template_cache(); + } else { + return Security::permissionFailure(null, 'Please log in as an administrator to flush the template cache.'); + } + } + + if (!is_array($templateList) && substr((string) $templateList, -3) == '.ss') { + $this->chosenTemplates['main'] = $templateList; + } else { + $this->chosenTemplates = SS_TemplateLoader::instance()->findTemplates( + $templateList, self::current_theme() + ); + //Debug::show($this->chosenTemplates); + } - if(!$this->chosenTemplates) { - $templateList = (is_array($templateList)) ? $templateList : array($templateList); - - user_error("None of these templates can be found in theme '" - . self::current_theme() . "': ". implode(".ss, ", $templateList) . ".ss", E_USER_WARNING); - } - } - - + if (!$this->chosenTemplates) { + $templateList = (is_array($templateList)) ? $templateList : array($templateList); + + user_error("None of these templates can be found in theme '" + . self::current_theme() . "': ". implode(".ss, ", $templateList) . ".ss", E_USER_WARNING); + } + } } diff --git a/code/tests/TestUserTemplatesExtension.php b/code/tests/TestUserTemplatesExtension.php index 71e9234..a70ec26 100644 --- a/code/tests/TestUserTemplatesExtension.php +++ b/code/tests/TestUserTemplatesExtension.php @@ -1,65 +1,68 @@ array("UserTemplatesExtension"), - 'Page_Controller' => 'UserTemplatesControllerExtension' - ); - - public function testCreateUserDefinedTemplate() { - $this->logInWithPermission(); - - $ut = new UserTemplate(); - $ut->Title = 'Template 1'; - $ut->Use = 'Layout'; - $ut->Content = 'UserTemplate 1 $Content'; - - $ut->write(); - - $page = Page::create(); - $page->Title = 'My page'; - $page->Content = 'PageContent'; - - $page->write(); - - $out = $page->renderWith(array('Page', 'Page')); - - $this->assertTrue(strpos($out, 'PageContent') > 0); - $this->assertTrue(strpos($out, 'UserTemplate 1') === false); - - // bind the user template - $page->LayoutTemplateID = $ut->ID; - $page->write(); - - $ctrl = Page_Controller::create($page); - $viewer = $ctrl->getViewer('index'); - - $out = $viewer->process($ctrl); - $this->assertTrue(strpos($out, 'UserTemplate 1 PageContent') > 0); - } - - public function testRegenerateOnDelete() { - $this->logInWithPermission(); - - $ut = new UserTemplate(); - $ut->Title = 'Template 1'; - $ut->Use = 'Layout'; - $ut->Content = 'UserTemplate 1 $Content'; - - $ut->write(); - - $file = $ut->getTemplateFile(); - - clearstatcache(); - $size = filesize($file); - $this->assertTrue($size > 0); - - unlink($file); - - $file = $ut->getTemplateFile(); - - clearstatcache(); - $size = filesize($file); - $this->assertTrue($size > 0); - } -} \ No newline at end of file +class TestUserTemplatesExtension extends SapphireTest +{ + protected $requiredExtensions = array( + "SiteTree" => array("UserTemplatesExtension"), + 'Page_Controller' => 'UserTemplatesControllerExtension' + ); + + public function testCreateUserDefinedTemplate() + { + $this->logInWithPermission(); + + $ut = new UserTemplate(); + $ut->Title = 'Template 1'; + $ut->Use = 'Layout'; + $ut->Content = 'UserTemplate 1 $Content'; + + $ut->write(); + + $page = Page::create(); + $page->Title = 'My page'; + $page->Content = 'PageContent'; + + $page->write(); + + $out = $page->renderWith(array('Page', 'Page')); + + $this->assertTrue(strpos($out, 'PageContent') > 0); + $this->assertTrue(strpos($out, 'UserTemplate 1') === false); + + // bind the user template + $page->LayoutTemplateID = $ut->ID; + $page->write(); + + $ctrl = Page_Controller::create($page); + $viewer = $ctrl->getViewer('index'); + + $out = $viewer->process($ctrl); + $this->assertTrue(strpos($out, 'UserTemplate 1 PageContent') > 0); + } + + public function testRegenerateOnDelete() + { + $this->logInWithPermission(); + + $ut = new UserTemplate(); + $ut->Title = 'Template 1'; + $ut->Use = 'Layout'; + $ut->Content = 'UserTemplate 1 $Content'; + + $ut->write(); + + $file = $ut->getTemplateFile(); + + clearstatcache(); + $size = filesize($file); + $this->assertTrue($size > 0); + + unlink($file); + + $file = $ut->getTemplateFile(); + + clearstatcache(); + $size = filesize($file); + $this->assertTrue($size > 0); + } +}