From eaa906f8fc49df3426468f23c0531c3a5055e833 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 20 Feb 2009 00:13:09 -0500 Subject: [PATCH] Implement configuration inheritance. Signed-off-by: Edward Z. Yang --- NEWS | 3 +++ TODO | 2 -- library/HTMLPurifier/Config.php | 32 +++++++++++++++++++++---------- tests/HTMLPurifier/ConfigTest.php | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 1a49f7fd..fa2a65c3 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,9 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier docs/dev-config-bcbreaks.txt for details; in essence, anything that had both namespace and directive now have a single unified key. ! More robust support for name="" and id="" +! HTMLPurifier_Config::inherit($config) allows you to inherit one + configuration, and have changes to that configuration be propagated + to all of its children. 3.3.0, released 2009-02-16 ! Implement CSS property 'overflow' when %CSS.AllowTricky is true. diff --git a/TODO b/TODO index 770b46d0..df63420c 100644 --- a/TODO +++ b/TODO @@ -14,8 +14,6 @@ afraid to cast your vote for the next feature to be implemented! - Investigate how early internal structures can be accessed; this would prevent structures from being parsed and serialized multiple times. - Built-in support for target="_blank" on all external links -- Convert configuration to allow an arbitrary number of namespaces; - then rename as appropriate. FUTURE VERSIONS --------------- diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php index ab925c91..be8bd0b8 100644 --- a/library/HTMLPurifier/Config.php +++ b/library/HTMLPurifier/Config.php @@ -84,8 +84,9 @@ class HTMLPurifier_Config * @param $definition HTMLPurifier_ConfigSchema that defines what directives * are allowed. */ - public function __construct($definition) { - $this->plist = new HTMLPurifier_PropertyList($definition->defaultPlist); + public function __construct($definition, $parent = null) { + $parent = $parent ? $parent : $definition->defaultPlist; + $this->plist = new HTMLPurifier_PropertyList($parent); $this->def = $definition; // keep a copy around for checking $this->parser = new HTMLPurifier_VarParser_Flexible(); } @@ -114,6 +115,16 @@ class HTMLPurifier_Config return $ret; } + /** + * Creates a new config object that inherits from a previous one. + * @param HTMLPurifier_Config $config Configuration object to inherit + * from. + * @return HTMLPurifier_Config object with $config as its parent. + */ + public static function inherit(HTMLPurifier_Config $config) { + return new HTMLPurifier_Config($config->def, $config->plist); + } + /** * Convenience constructor that creates a default configuration object. * @return Default HTMLPurifier_Config object. @@ -126,7 +137,6 @@ class HTMLPurifier_Config /** * Retreives a value from the configuration. - * @param $namespace String namespace * @param $key String key */ public function get($key, $a = null) { @@ -134,7 +144,7 @@ class HTMLPurifier_Config $this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING); $key = "$key.$a"; } - if (!$this->finalized) $this->autoFinalize ? $this->finalize() : $this->plist->squash(true); + if (!$this->finalized) $this->autoFinalize(); if (!isset($this->def->info[$key])) { // can't add % due to SimpleTest bug $this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key), @@ -155,7 +165,7 @@ class HTMLPurifier_Config * @param $namespace String namespace */ public function getBatch($namespace) { - if (!$this->finalized) $this->autoFinalize ? $this->finalize() : $this->plist->squash(true); + if (!$this->finalized) $this->autoFinalize(); $full = $this->getAll(); if (!isset($full[$namespace])) { $this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace), @@ -196,7 +206,7 @@ class HTMLPurifier_Config * Retrieves all directives, organized by namespace */ public function getAll() { - if (!$this->finalized) $this->autoFinalize ? $this->finalize() : $this->plist->squash(true); + if (!$this->finalized) $this->autoFinalize(); $ret = array(); foreach ($this->plist->squash() as $name => $value) { list($ns, $key) = explode('.', $name, 2); @@ -207,7 +217,6 @@ class HTMLPurifier_Config /** * Sets a value to configuration. - * @param $namespace String namespace * @param $key String key * @param $value Mixed value */ @@ -316,7 +325,7 @@ class HTMLPurifier_Config * @param $raw Whether or not definition should be returned raw */ public function getDefinition($type, $raw = false) { - if (!$this->finalized) $this->autoFinalize ? $this->finalize() : $this->plist->squash(true); + if (!$this->finalized) $this->autoFinalize(); $factory = HTMLPurifier_DefinitionCacheFactory::instance(); $cache = $factory->create($type, $this); if (!$raw) { @@ -376,7 +385,6 @@ class HTMLPurifier_Config foreach ($config_array as $key => $value) { $key = str_replace('_', '.', $key); if (strpos($key, '.') !== false) { - list($namespace, $directive) = explode(".", $key, 2); $this->set($key, $value); } else { $namespace = $key; @@ -505,7 +513,11 @@ class HTMLPurifier_Config * already finalized */ public function autoFinalize() { - if (!$this->finalized && $this->autoFinalize) $this->finalize(); + if ($this->autoFinalize) { + $this->finalize(); + } else { + $this->plist->squash(true); + } } /** diff --git a/tests/HTMLPurifier/ConfigTest.php b/tests/HTMLPurifier/ConfigTest.php index 02ea80d8..103ed5bd 100644 --- a/tests/HTMLPurifier/ConfigTest.php +++ b/tests/HTMLPurifier/ConfigTest.php @@ -437,6 +437,20 @@ class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness $this->expectError('Using deprecated API: use $config->get(\'Foo.Bar\') instead'); $this->assertIdentical($config->get('Foo', 'Bar'), 4); } + + function testInherit() { + $this->schema->add('Phantom.Masked', 25, 'int', false); + $this->schema->add('Phantom.Unmasked', 89, 'int', false); + $this->schema->add('Phantom.Latemasked', 11, 'int', false); + $config = new HTMLPurifier_Config($this->schema); + $config->set('Phantom.Masked', 800); + $subconfig = HTMLPurifier_Config::inherit($config); + $config->set('Phantom.Latemasked', 100, 'int', false); + $this->assertIdentical($subconfig->get('Phantom.Masked'), 800); + $this->assertIdentical($subconfig->get('Phantom.Unmasked'), 89); + $this->assertIdentical($subconfig->get('Phantom.Latemasked'), 100); + } + } // vim: et sw=4 sts=4