]>
Commit | Line | Data |
---|---|---|
010efc9b AD |
1 | <?php |
2 | ||
3 | /** | |
4 | * @todo Unit test | |
5 | */ | |
6 | class HTMLPurifier_ContentSets | |
7 | { | |
8 | ||
9 | /** | |
10 | * List of content set strings (pipe seperators) indexed by name. | |
11 | */ | |
12 | public $info = array(); | |
13 | ||
14 | /** | |
15 | * List of content set lookups (element => true) indexed by name. | |
16 | * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets | |
17 | */ | |
18 | public $lookup = array(); | |
19 | ||
20 | /** | |
21 | * Synchronized list of defined content sets (keys of info) | |
22 | */ | |
23 | protected $keys = array(); | |
24 | /** | |
25 | * Synchronized list of defined content values (values of info) | |
26 | */ | |
27 | protected $values = array(); | |
28 | ||
29 | /** | |
30 | * Merges in module's content sets, expands identifiers in the content | |
31 | * sets and populates the keys, values and lookup member variables. | |
32 | * @param $modules List of HTMLPurifier_HTMLModule | |
33 | */ | |
34 | public function __construct($modules) { | |
35 | if (!is_array($modules)) $modules = array($modules); | |
36 | // populate content_sets based on module hints | |
37 | // sorry, no way of overloading | |
38 | foreach ($modules as $module_i => $module) { | |
39 | foreach ($module->content_sets as $key => $value) { | |
40 | $temp = $this->convertToLookup($value); | |
41 | if (isset($this->lookup[$key])) { | |
42 | // add it into the existing content set | |
43 | $this->lookup[$key] = array_merge($this->lookup[$key], $temp); | |
44 | } else { | |
45 | $this->lookup[$key] = $temp; | |
46 | } | |
47 | } | |
48 | } | |
49 | $old_lookup = false; | |
50 | while ($old_lookup !== $this->lookup) { | |
51 | $old_lookup = $this->lookup; | |
52 | foreach ($this->lookup as $i => $set) { | |
53 | $add = array(); | |
54 | foreach ($set as $element => $x) { | |
55 | if (isset($this->lookup[$element])) { | |
56 | $add += $this->lookup[$element]; | |
57 | unset($this->lookup[$i][$element]); | |
58 | } | |
59 | } | |
60 | $this->lookup[$i] += $add; | |
61 | } | |
62 | } | |
63 | ||
64 | foreach ($this->lookup as $key => $lookup) { | |
65 | $this->info[$key] = implode(' | ', array_keys($lookup)); | |
66 | } | |
67 | $this->keys = array_keys($this->info); | |
68 | $this->values = array_values($this->info); | |
69 | } | |
70 | ||
71 | /** | |
72 | * Accepts a definition; generates and assigns a ChildDef for it | |
73 | * @param $def HTMLPurifier_ElementDef reference | |
74 | * @param $module Module that defined the ElementDef | |
75 | */ | |
76 | public function generateChildDef(&$def, $module) { | |
77 | if (!empty($def->child)) return; // already done! | |
78 | $content_model = $def->content_model; | |
79 | if (is_string($content_model)) { | |
80 | // Assume that $this->keys is alphanumeric | |
81 | $def->content_model = preg_replace_callback( | |
82 | '/\b(' . implode('|', $this->keys) . ')\b/', | |
83 | array($this, 'generateChildDefCallback'), | |
84 | $content_model | |
85 | ); | |
86 | //$def->content_model = str_replace( | |
87 | // $this->keys, $this->values, $content_model); | |
88 | } | |
89 | $def->child = $this->getChildDef($def, $module); | |
90 | } | |
91 | ||
92 | public function generateChildDefCallback($matches) { | |
93 | return $this->info[$matches[0]]; | |
94 | } | |
95 | ||
96 | /** | |
97 | * Instantiates a ChildDef based on content_model and content_model_type | |
98 | * member variables in HTMLPurifier_ElementDef | |
99 | * @note This will also defer to modules for custom HTMLPurifier_ChildDef | |
100 | * subclasses that need content set expansion | |
101 | * @param $def HTMLPurifier_ElementDef to have ChildDef extracted | |
102 | * @return HTMLPurifier_ChildDef corresponding to ElementDef | |
103 | */ | |
104 | public function getChildDef($def, $module) { | |
105 | $value = $def->content_model; | |
106 | if (is_object($value)) { | |
107 | trigger_error( | |
108 | 'Literal object child definitions should be stored in '. | |
109 | 'ElementDef->child not ElementDef->content_model', | |
110 | E_USER_NOTICE | |
111 | ); | |
112 | return $value; | |
113 | } | |
114 | switch ($def->content_model_type) { | |
115 | case 'required': | |
116 | return new HTMLPurifier_ChildDef_Required($value); | |
117 | case 'optional': | |
118 | return new HTMLPurifier_ChildDef_Optional($value); | |
119 | case 'empty': | |
120 | return new HTMLPurifier_ChildDef_Empty(); | |
121 | case 'custom': | |
122 | return new HTMLPurifier_ChildDef_Custom($value); | |
123 | } | |
124 | // defer to its module | |
125 | $return = false; | |
126 | if ($module->defines_child_def) { // save a func call | |
127 | $return = $module->getChildDef($def); | |
128 | } | |
129 | if ($return !== false) return $return; | |
130 | // error-out | |
131 | trigger_error( | |
132 | 'Could not determine which ChildDef class to instantiate', | |
133 | E_USER_ERROR | |
134 | ); | |
135 | return false; | |
136 | } | |
137 | ||
138 | /** | |
139 | * Converts a string list of elements separated by pipes into | |
140 | * a lookup array. | |
141 | * @param $string List of elements | |
142 | * @return Lookup array of elements | |
143 | */ | |
144 | protected function convertToLookup($string) { | |
145 | $array = explode('|', str_replace(' ', '', $string)); | |
146 | $ret = array(); | |
147 | foreach ($array as $i => $k) { | |
148 | $ret[$k] = true; | |
149 | } | |
150 | return $ret; | |
151 | } | |
152 | ||
153 | } | |
154 | ||
155 | // vim: et sw=4 sts=4 |