diff --git a/core/ManifestBuilder.php b/core/ManifestBuilder.php index edf5c26c0..5538f2ffe 100644 --- a/core/ManifestBuilder.php +++ b/core/ManifestBuilder.php @@ -153,7 +153,7 @@ class ManifestBuilder { * * @param string $baseDir Optional: Absolute path to theme directory for testing e.g. "/Users/sharvey/Sites/test24/themes" * @param boolean $includeSubThemes If set to TRUE, sub-themes such as "blackcandy_blog" are included too - * @return array indexed array of theme directories + * @return array Listing of theme directories */ public static function get_themes($baseDir = null, $includeSubThemes = false) { // If no base directory specified, the default is the project root @@ -168,7 +168,7 @@ class ManifestBuilder { if(strpos($file, '_') === false) { $include = true; } - if($include) $themes[] = $file; + if($include) $themes[$file] = $file; } } closedir($handle); diff --git a/core/SSViewer.php b/core/SSViewer.php index 11a044229..5c67392c5 100755 --- a/core/SSViewer.php +++ b/core/SSViewer.php @@ -87,6 +87,11 @@ class SSViewer { */ protected static $current_theme = null; + /** + * @var string + */ + protected static $cached_theme = null; + /** * Create a template from a string instead of a .ss file * @@ -106,8 +111,18 @@ class SSViewer { /** * @return string */ - static function current_theme() { - return self::$current_theme; + static function current_theme($cached = true) { + if($cached && self::$cached_theme) { + // First case is to return the cached user theme so we don't requery SiteConfig again + return self::$cached_theme; + } else { + // Need to refresh the cache from the SiteConfig + $theme = SiteConfig::current_site_config()->Theme; + self::$cached_theme = $theme; + } + // Fall back to the default SSViewer::set_theme() behaviour + if(!$theme) $theme = self::$current_theme; + return $theme; } /** @@ -141,13 +156,13 @@ class SSViewer { else $templateFolder = null; // Use the theme template if available - if(self::$current_theme && isset($_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme])) { + if(self::current_theme() && isset($_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()])) { $this->chosenTemplates = array_merge( - $_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme], + $_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()], $this->chosenTemplates ); - if(isset($_GET['debug_request'])) Debug::message("Found template '$template' from main theme '" . self::$current_theme . "': " . var_export($_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme], true)); + if(isset($_GET['debug_request'])) Debug::message("Found template '$template' from main theme '" . self::current_theme() . "': " . var_export($_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()], true)); } // Fall back to unthemed base templates @@ -257,8 +272,8 @@ class SSViewer { */ public static function getTemplateFileByType($identifier, $type) { global $_TEMPLATE_MANIFEST; - if(self::$current_theme && isset($_TEMPLATE_MANIFEST[$identifier]['themes'][self::$current_theme][$type])) { - return $_TEMPLATE_MANIFEST[$identifier]['themes'][self::$current_theme][$type]; + if(self::current_theme() && isset($_TEMPLATE_MANIFEST[$identifier]['themes'][self::current_theme()][$type])) { + return $_TEMPLATE_MANIFEST[$identifier]['themes'][self::current_theme()][$type]; } else if(isset($_TEMPLATE_MANIFEST[$identifier][$type])){ return $_TEMPLATE_MANIFEST[$identifier][$type]; } else { diff --git a/core/model/SiteConfig.php b/core/model/SiteConfig.php index 3b5fd5d53..a63fbe2cd 100644 --- a/core/model/SiteConfig.php +++ b/core/model/SiteConfig.php @@ -17,6 +17,7 @@ class SiteConfig extends DataObject { static $db = array( "Title" => "Varchar(255)", "Tagline" => "Varchar(255)", + "Theme" => "Varchar(255)", "CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')", "CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')", "CanCreateTopLevelType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')", @@ -28,6 +29,12 @@ class SiteConfig extends DataObject { "CreateTopLevelGroups" => "Group" ); + protected static $disabled_themes = array(); + + public static function disable_theme($theme) { + self::$disabled_themes[$theme] = $theme; + } + /** * Get the fields that are sent to the CMS. In * your decorators: updateEditFormFields(&$fields) @@ -39,7 +46,8 @@ class SiteConfig extends DataObject { new TabSet("Root", new Tab('Main', $titleField = new TextField("Title", _t('SiteConfig.SITETITLE', "Site title")), - $taglineField = new TextField("Tagline", _t('SiteConfig.SITETAGLINE', "Site Tagline/Slogan")) + $taglineField = new TextField("Tagline", _t('SiteConfig.SITETAGLINE', "Site Tagline/Slogan")), + new DropdownField("Theme", _t('SiteConfig.THEME', 'Theme'), $this->getAvailableThemes(), '', null, _t('SiteConfig.DEFAULTTHEME', '(Use default theme)')) ), new Tab('Access', new HeaderField('WhoCanViewHeader', _t('SiteConfig.VIEWHEADER', "Who can view pages on this site?"), 2), @@ -89,6 +97,19 @@ class SiteConfig extends DataObject { $this->extend('updateEditFormFields', $fields); return $fields; } + + /** + * Get all available themes that haven't been marked as disabled. + * @param string $baseDir Optional alternative theme base directory for testing + * @return array of theme directory names + */ + public function getAvailableThemes($baseDir = null) { + $themes = ManifestBuilder::get_themes($baseDir); + foreach(self::$disabled_themes as $theme) { + if(isset($themes[$theme])) unset($themes[$theme]); + } + return $themes; + } /** * Get the actions that are sent to the CMS. In diff --git a/tests/SSViewerTest.php b/tests/SSViewerTest.php index 62215bc6e..00bdc734e 100644 --- a/tests/SSViewerTest.php +++ b/tests/SSViewerTest.php @@ -1,6 +1,30 @@ Theme; + $config->Theme = ''; + $config->write(); + + SSViewer::set_theme('mytheme'); + $this->assertEquals('mytheme', SSViewer::current_theme(), 'Current theme is the default - user has not defined one'); + + $config->Theme = 'myusertheme'; + $config->write(); + $this->assertEquals('myusertheme', SSViewer::current_theme(), 'Current theme is a user defined one'); + + // Set the theme back to the original + $config->Theme = $oldTheme; + $config->write(); + } + /** * Test that a template without a tag still renders. */ diff --git a/tests/model/SiteConfigTest.php b/tests/model/SiteConfigTest.php index 9008b7c4d..758dea537 100644 --- a/tests/model/SiteConfigTest.php +++ b/tests/model/SiteConfigTest.php @@ -53,6 +53,27 @@ class SiteConfigTest extends SapphireTest { $this->assertFalse($pageEn->canEdit($translatorDe)); $this->assertTrue($pageEn->canEdit($translatorEn)); } + + function testAvailableThemes() { + $config = SiteConfig::current_site_config(); + $ds = DIRECTORY_SEPARATOR; + $testThemeBaseDir = TEMP_FOLDER . $ds . 'test-themes'; + + if(file_exists($testThemeBaseDir)) Filesystem::removeFolder($testThemeBaseDir); + mkdir($testThemeBaseDir); + mkdir($testThemeBaseDir . $ds . 'blackcandy'); + mkdir($testThemeBaseDir . $ds . 'blackcandy_blog'); + mkdir($testThemeBaseDir . $ds . 'darkshades'); + mkdir($testThemeBaseDir . $ds . 'darkshades_blog'); + + $themes = $config->getAvailableThemes($testThemeBaseDir); + $this->assertContains('blackcandy', $themes, 'Test themes contain blackcandy theme'); + $this->assertContains('darkshades', $themes, 'Test themes contain darkshades theme'); + + SiteConfig::disable_theme('darkshades'); + $themes = $config->getAvailableThemes($testThemeBaseDir); + $this->assertFalse(in_array('darkshades', $themes), 'Darkshades was disabled - it is no longer available'); + } } ?> \ No newline at end of file