diff --git a/docs/en/02_Developer_Guides/01_Templates/How_Tos/03_Disable_Anchor_Links.md b/docs/en/02_Developer_Guides/01_Templates/How_Tos/03_Disable_Anchor_Links.md index 3e998aaf0..c7716f203 100644 --- a/docs/en/02_Developer_Guides/01_Templates/How_Tos/03_Disable_Anchor_Links.md +++ b/docs/en/02_Developer_Guides/01_Templates/How_Tos/03_Disable_Anchor_Links.md @@ -42,10 +42,10 @@ Or, a better way is to call this just for the rendering phase of this particular ```php public function RenderCustomTemplate() { - Config::inst()->update('SSViewer', 'rewrite_hash_links', false); + SSViewer::setRewriteHashLinks(false); $html = $this->renderWith('MyCustomTemplate'); - Config::inst()->update('SSViewer', 'rewrite_hash_links', true); + SSViewer::setRewriteHashLinks(true); return $html; } -``` \ No newline at end of file +``` diff --git a/src/Control/ContentNegotiator.php b/src/Control/ContentNegotiator.php index aed1b0bfb..728fd466d 100644 --- a/src/Control/ContentNegotiator.php +++ b/src/Control/ContentNegotiator.php @@ -57,6 +57,13 @@ class ContentNegotiator * @var bool */ private static $enabled = false; + + /** + * @config + * + * @var bool + */ + protected static $current_enabled = null; /** * @config @@ -84,12 +91,37 @@ class ContentNegotiator return false; } - if (static::config()->get('enabled')) { + if (ContentNegotiator::getEnabled()) { return true; } else { return (substr($response->getBody(), 0, 5) == '<' . '?xml'); } } + + /** + * Gets the current enabled status, if it is not set this will fallback to config + * + * @return bool + */ + public static function getEnabled() + { + if (!isset(self::$current_enabled)) { + self::$current_enabled = ContentNegotiator::config()->get('enabled'); + } + return self::$current_enabled; + } + + /** + * Sets the current enabled status + * + * @param bool $enabled + */ + public static function setEnabled($enabled) + { + if (isset($enabled)) { + self::$current_enabled = $enabled; + } + } /** * @param HTTPResponse $response diff --git a/src/Forms/HTMLEditor/HTMLEditorConfig.php b/src/Forms/HTMLEditor/HTMLEditorConfig.php index 50a5124a8..df4546997 100644 --- a/src/Forms/HTMLEditor/HTMLEditorConfig.php +++ b/src/Forms/HTMLEditor/HTMLEditorConfig.php @@ -58,6 +58,13 @@ abstract class HTMLEditorConfig * @var array */ private static $user_themes = []; + + /** + * List of the current themes set for this config + * + * @var array + */ + protected static $current_themes = null; /** * Get the HTMLEditorConfig object for the given identifier. This is a correct way to get an HTMLEditorConfig @@ -95,7 +102,31 @@ abstract class HTMLEditorConfig } return $config; } - + + /** + * Gets the current themes, if it is not set this will fallback to config + * @return array + */ + public static function getThemes() + { + if (!isset(self::$current_themes)) { + self::$current_themes = self::config()->get('user_themes'); + } + return self::$current_themes; + } + + /** + * Sets the current theme + * + * @param array $themes + */ + public static function setThemes($themes) + { + if (isset($themes)) { + self::$current_themes = $themes; + } + } + /** * Set the currently active configuration object. Note that the existing active * config will not be renamed to the new identifier. diff --git a/src/Forms/HTMLEditor/TinyMCEConfig.php b/src/Forms/HTMLEditor/TinyMCEConfig.php index 84743308a..bec47c21c 100644 --- a/src/Forms/HTMLEditor/TinyMCEConfig.php +++ b/src/Forms/HTMLEditor/TinyMCEConfig.php @@ -635,7 +635,7 @@ class TinyMCEConfig extends HTMLEditorConfig } // Themed editor.css - $themes = $this->config()->get('user_themes') ?: SSViewer::get_themes(); + $themes = HTMLEditorConfig::getThemes() ?: SSViewer::get_themes(); $themedEditor = ThemeResourceLoader::inst()->findThemedCSS('editor', $themes); if ($themedEditor) { $editor[] = Director::absoluteURL($themedEditor); diff --git a/src/View/SSTemplateParser.peg b/src/View/SSTemplateParser.peg index 5c1e84dc6..463e7ef16 100644 --- a/src/View/SSTemplateParser.peg +++ b/src/View/SSTemplateParser.peg @@ -1213,7 +1213,7 @@ class SSTemplateParser extends Parser implements TemplateParser // TODO: This is pretty ugly & gets applied on all files not just html. I wonder if we can make this // non-dynamically calculated $code = <<<'EOC' -(\SilverStripe\View\SSViewer::config()->get('rewrite_hash_links') +(\SilverStripe\View\SSViewer::getRewriteHashLinksDefault() ? \SilverStripe\Core\Convert::raw2att( preg_replace("/^(\\/)+/", "/", $_SERVER['REQUEST_URI'] ) ) : "") EOC; diff --git a/src/View/SSTemplateParser.php b/src/View/SSTemplateParser.php index 559c7bbb0..f1af5ca0e 100644 --- a/src/View/SSTemplateParser.php +++ b/src/View/SSTemplateParser.php @@ -1118,7 +1118,7 @@ class SSTemplateParser extends Parser implements TemplateParser $matchrule = "QuotedString"; $result = $this->construct($matchrule, $matchrule, null); $_143 = NULL; do { - $stack[] = $result; $result = $this->construct( $matchrule, "q" ); + $stack[] = $result; $result = $this->construct( $matchrule, "q" ); if (( $subres = $this->rx( '/[\'"]/' ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result; $result = array_pop($stack); @@ -1128,7 +1128,7 @@ class SSTemplateParser extends Parser implements TemplateParser $result = array_pop($stack); $_143 = FALSE; break; } - $stack[] = $result; $result = $this->construct( $matchrule, "String" ); + $stack[] = $result; $result = $this->construct( $matchrule, "String" ); if (( $subres = $this->rx( '/ (\\\\\\\\ | \\\\. | [^'.$this->expression($result, $stack, 'q').'\\\\])* /' ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result; $result = array_pop($stack); @@ -1481,7 +1481,7 @@ class SSTemplateParser extends Parser implements TemplateParser $pos_200 = $this->pos; $_199 = NULL; do { - $stack[] = $result; $result = $this->construct( $matchrule, "Not" ); + $stack[] = $result; $result = $this->construct( $matchrule, "Not" ); if (( $subres = $this->literal( 'not' ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result; $result = array_pop($stack); @@ -1876,7 +1876,7 @@ class SSTemplateParser extends Parser implements TemplateParser else { $_275 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } else { $_275 = FALSE; break; } - $stack[] = $result; $result = $this->construct( $matchrule, "Call" ); + $stack[] = $result; $result = $this->construct( $matchrule, "Call" ); $_271 = NULL; do { $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; @@ -2363,7 +2363,7 @@ class SSTemplateParser extends Parser implements TemplateParser $_364 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $stack[] = $result; $result = $this->construct( $matchrule, "Conditional" ); + $stack[] = $result; $result = $this->construct( $matchrule, "Conditional" ); $_360 = NULL; do { $_358 = NULL; @@ -2769,7 +2769,7 @@ class SSTemplateParser extends Parser implements TemplateParser if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } else { $_492 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $stack[] = $result; $result = $this->construct( $matchrule, "CacheTag" ); + $stack[] = $result; $result = $this->construct( $matchrule, "CacheTag" ); $_445 = NULL; do { $_443 = NULL; @@ -2828,7 +2828,7 @@ class SSTemplateParser extends Parser implements TemplateParser $_461 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $stack[] = $result; $result = $this->construct( $matchrule, "Conditional" ); + $stack[] = $result; $result = $this->construct( $matchrule, "Conditional" ); $_457 = NULL; do { $_455 = NULL; @@ -3768,7 +3768,7 @@ class SSTemplateParser extends Parser implements TemplateParser unset( $pos_622 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $stack[] = $result; $result = $this->construct( $matchrule, "Zap" ); + $stack[] = $result; $result = $this->construct( $matchrule, "Zap" ); if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result; $result = array_pop($stack); @@ -4178,7 +4178,7 @@ class SSTemplateParser extends Parser implements TemplateParser if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } else { $_680 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $stack[] = $result; $result = $this->construct( $matchrule, "Tag" ); + $stack[] = $result; $result = $this->construct( $matchrule, "Tag" ); $_674 = NULL; do { if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; } @@ -4834,7 +4834,7 @@ class SSTemplateParser extends Parser implements TemplateParser // TODO: This is pretty ugly & gets applied on all files not just html. I wonder if we can make this // non-dynamically calculated $code = <<<'EOC' -(\SilverStripe\View\SSViewer::config()->get('rewrite_hash_links') +(\SilverStripe\View\SSViewer::getRewriteHashLinksDefault() ? \SilverStripe\Core\Convert::raw2att( preg_replace("/^(\\/)+/", "/", $_SERVER['REQUEST_URI'] ) ) : "") EOC; diff --git a/src/View/SSViewer.php b/src/View/SSViewer.php index c69953243..9aa46fb88 100644 --- a/src/View/SSViewer.php +++ b/src/View/SSViewer.php @@ -2,6 +2,7 @@ namespace SilverStripe\View; +use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\ClassInfo; use Psr\SimpleCache\CacheInterface; @@ -49,27 +50,40 @@ class SSViewer implements Flushable const DEFAULT_THEME = '$default'; /** - * @config - * @var string A list (highest priority first) of themes to use + * A list (highest priority first) of themes to use * Only used when {@link $theme_enabled} is set to TRUE. + * + * @config + * @var string */ private static $themes = []; /** + * Overridden value of $themes config + * + * @var array + */ + protected static $current_themes = null; + + /** + * The used "theme", which usually consists of templates, images and stylesheets. + * Only used when {@link $theme_enabled} is set to TRUE, and $themes is empty + * * @deprecated 4.0..5.0 * @config - * @var string The used "theme", which usually consists of templates, images and stylesheets. - * Only used when {@link $theme_enabled} is set to TRUE, and $themes is empty + * @var string */ private static $theme = null; /** - * @config - * @var boolean Use the theme. Set to FALSE in order to disable themes, + * Use the theme. Set to FALSE in order to disable themes, * which can be useful for scenarios where theme overrides are temporarily undesired, * such as an administrative interface separate from the website theme. * It retains the theme settings to be re-enabled, for example when a website content * needs to be rendered from within this administrative interface. + * + * @config + * @var bool */ private static $theme_enabled = true; @@ -83,53 +97,75 @@ class SSViewer implements Flushable /** * @config - * @var boolean $source_file_comments + * @var bool */ private static $source_file_comments = false; /** + * Set if hash links should be rewritten + * * @config - * @var boolean + * @var bool */ private static $rewrite_hash_links = true; /** + * Overridden value of rewrite_hash_links config + * + * @var bool + */ + protected static $current_rewrite_hash_links = null; + + /** + * Instance variable to disable rewrite_hash_links (overrides global default) + * Leave null to use global state. + * + * @var bool|null + */ + protected $rewriteHashlinks = null; + + /** + * @internal * @ignore */ private static $template_cache_flushed = false; /** + * @internal * @ignore */ private static $cacheblock_cache_flushed = false; /** - * @var array $topLevel List of items being processed + * List of items being processed + * + * @var array */ protected static $topLevel = []; /** - * @var array $templates List of templates to select from + * List of templates to select from + * + * @var array */ protected $templates = null; /** - * @var string $chosen Absolute path to chosen template file + * Absolute path to chosen template file + * + * @var string */ protected $chosen = null; /** - * @var array Templates to use when looking up 'Layout' or 'Content' + * Templates to use when looking up 'Layout' or 'Content' + * + * @var array */ protected $subTemplates = null; /** - * @var boolean - */ - protected $rewriteHashlinks = true; - - /** - * @var boolean + * @var bool */ protected $includeRequirements = true; @@ -315,6 +351,55 @@ class SSViewer implements Flushable return null; } + /** + * Check if rewrite hash links are enabled on this instance + * + * @return bool + */ + public function getRewriteHashLinks() + { + if (isset($this->rewriteHashlinks)) { + return $this->rewriteHashlinks; + } + return static::getRewriteHashLinksDefault(); + } + + /** + * Set if hash links are rewritten for this instance + * + * @param bool $rewrite + * @return $this + */ + public function setRewriteHashLinks($rewrite) + { + $this->rewriteHashlinks = $rewrite; + return $this; + } + + /** + * Get default value for rewrite hash links for all modules + * + * @return bool + */ + public static function getRewriteHashLinksDefault() + { + // Check if config overridden + if (isset(self::$current_rewrite_hash_links)) { + return self::$current_rewrite_hash_links; + } + return Config::inst()->get(static::class, 'rewrite_hash_links'); + } + + /** + * Set default rewrite hash links + * + * @param bool $rewrite + */ + public static function setRewriteHashLinksDefault($rewrite) + { + self::$current_rewrite_hash_links = $rewrite; + } + /** * @param string|array $templates */ @@ -364,7 +449,7 @@ class SSViewer implements Flushable * * @param array|string $templates * - * @return boolean + * @return bool */ public static function hasTemplate($templates) { @@ -374,11 +459,12 @@ class SSViewer implements Flushable /** * Call this to disable rewriting of links. This is useful in Ajax applications. * It returns the SSViewer objects, so that you can call new SSViewer("X")->dontRewriteHashlinks()->process(); + * + * @return $this */ public function dontRewriteHashlinks() { - $this->rewriteHashlinks = false; - SSViewer::config()->update('rewrite_hash_links', false); + $this->setRewriteHashLinks(false); return $this; } @@ -467,7 +553,7 @@ class SSViewer implements Flushable /** * Flag whether to include the requirements in this response. * - * @param boolean + * @param bool */ public function includeRequirements($incl = true) { @@ -528,6 +614,11 @@ class SSViewer implements Flushable */ public function process($item, $arguments = null, $inheritedScope = null) { + // Set hashlinks and temporarily modify global state + $rewrite = $this->getRewriteHashLinks(); + $origRewriteDefault = static::getRewriteHashLinksDefault(); + static::setRewriteHashLinksDefault($rewrite); + SSViewer::$topLevel[] = $item; $template = $this->chosen; @@ -581,9 +672,7 @@ class SSViewer implements Flushable array_pop(SSViewer::$topLevel); // If we have our crazy base tag, then fix # links referencing the current page. - - $rewrite = SSViewer::config()->uninherited('rewrite_hash_links'); - if ($this->rewriteHashlinks && $rewrite) { + if ($rewrite) { if (strpos($output, 'update('rewrite_hash_links', true); + SSViewer::setRewriteHashLinksDefault(true); $_SERVER['HTTP_HOST'] = 'www.mysite.com'; $_SERVER['REQUEST_URI'] = '//file.com?foo"onclick="alert(\'xss\')""'; @@ -1744,7 +1744,7 @@ after' public function testRewriteHashlinksInPhpMode() { - SSViewer::config()->update('rewrite_hash_links', 'php'); + SSViewer::setRewriteHashLinksDefault('php'); $tmplFile = TEMP_FOLDER . '/SSViewerTest_testRewriteHashlinksInPhpMode_' . sha1(rand()) . '.ss';