DOMComment 和 DOMXPath的应用sample
symfony 1.0版本中的表单重填(当提交表单出现error的时候,要在表单中显示之前用户的输入)中的核心类:
/lib/symfony/util/sfFillInForm.class.php
1 <?php
2
3 /*
4 * This file is part of the symfony package.
5 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11 /**
12 *
13 * @package symfony
14 * @subpackage util
15 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
16 * @version SVN: $Id: sfFillInForm.class.php 2976 2006-12-08 19:11:36Z fabien $
17 */
18 class sfFillInForm
19 {
20 protected
21 $converters = array(),
22 $skipFields = array(),
23 $types = array('text', 'checkbox', 'radio', 'hidden', 'password');
24
25 public function addConverter($callable, $fields)
26 {
27 foreach ((array) $fields as $field)
28 {
29 $this->converters[$field][] = $callable;
30 }
31 }
32
33 public function setSkipFields($fields)
34 {
35 $this->skipFields = $fields;
36 }
37
38 public function setTypes($types)
39 {
40 $this->types = $types;
41 }
42
43 public function fillInHtml($html, $formName, $formId, $values)
44 {
45 $dom = new DomDocument('1.0', sfConfig::get('sf_charset', 'UTF-8'));
46 @$dom->loadHTML($html);
47
48 $dom = $this->fillInDom($dom, $formName, $formId, $values);
49
50 return $dom->saveHTML();
51 }
52
53 public function fillInXml($xml, $formName, $formId, $values)
54 {
55 $dom = new DomDocument('1.0', sfConfig::get('sf_charset', 'UTF-8'));
56 @$dom->loadXML($xml);
57
58 $dom = $this->fillInDom($dom, $formName, $formId, $values);
59
60 return $dom->saveXML();
61 }
62
63 public function fillInDom($dom, $formName, $formId, $values)
64 {
65 $xpath = new DomXPath($dom);
66
67 $query = 'descendant::input[@name and (not(@type)';
68 foreach ($this->types as $type)
69 {
70 $query .= ' or @type="'.$type.'"';
71 }
72 $query .= ')] | descendant::textarea[@name] | descendant::select[@name]';
73
74 // find our form
75 if ($formName)
76 {
77 $xpath_query = '//form[@name="'.$formName.'"]';
78 }
79 elseif ($formId)
80 {
81 $xpath_query = '//form[@id="'.$formId.'"]';
82 }
83 else
84 {
85 $xpath_query = '//form';
86 }
87
88 $form = $xpath->query($xpath_query)->item(0);
89 if (!$form)
90 {
91 if (!$formName && !$formId)
92 {
93 throw new sfException('No form found in this page');
94 }
95 else
96 {
97 throw new sfException(sprintf('The form "%s" cannot be found', $formName ? $formName : $formId));
98 }
99 }
100
101 foreach ($xpath->query($query, $form) as $element)
102 {
103 $name = (string) $element->getAttribute('name');
104 $value = (string) $element->getAttribute('value');
105 $type = (string) $element->getAttribute('type');
106
107 // skip fields
108 if (!$this->hasValue($values, $name) || in_array($name, $this->skipFields))
109 {
110 continue;
111 }
112
113 if ($element->nodeName == 'input')
114 {
115 if ($type == 'checkbox' || $type == 'radio')
116 {
117 // checkbox and radio
118 $element->removeAttribute('checked');
119 if ($this->hasValue($values, $name) && ($this->getValue($values, $name) == $value || !$element->hasAttribute('value')))
120 {
121 $element->setAttribute('checked', 'checked');
122 }
123 }
124 else
125 {
126 // text input
127 $element->removeAttribute('value');
128 if ($this->hasValue($values, $name))
129 {
130 $element->setAttribute('value', $this->escapeValue($this->getValue($values, $name), $name));
131 }
132 }
133 }
134 else if ($element->nodeName == 'textarea')
135 {
136 $el = $element->cloneNode(false);
137 $el->appendChild($dom->createTextNode($this->escapeValue($this->getValue($values, $name), $name)));
138 $element->parentNode->replaceChild($el, $element);
139 }
140 else if ($element->nodeName == 'select')
141 {
142 // select
143 $value = $this->getValue($values, $name);
144 $multiple = $element->hasAttribute('multiple');
145 foreach ($xpath->query('descendant::option', $element) as $option)
146 {
147 $option->removeAttribute('selected');
148 if ($multiple && is_array($value))
149 {
150 if (in_array($option->getAttribute('value'), $value))
151 {
152 $option->setAttribute('selected', 'selected');
153 }
154 }
155 else if ($value == $option->getAttribute('value'))
156 {
157 $option->setAttribute('selected', 'selected');
158 }
159 }
160 }
161 }
162
163 return $dom;
164 }
165
166 protected function hasValue($values, $name)
167 {
168 if (array_key_exists($name, $values))
169 {
170 return true;
171 }
172
173 return null !== sfToolkit::getArrayValueForPath($values, $name);
174 }
175
176 protected function getValue($values, $name)
177 {
178 if (array_key_exists($name, $values))
179 {
180 return $values[$name];
181 }
182
183 return sfToolkit::getArrayValueForPath($values, $name);
184 }
185
186 protected function escapeValue($value, $name)
187 {
188 if (function_exists('iconv') && strtolower(sfConfig::get('sf_charset')) != 'utf-8')
189 {
190 $new_value = iconv(sfConfig::get('sf_charset'), 'UTF-8', $value);
191 if (false !== $new_value)
192 {
193 $value = $new_value;
194 }
195 }
196
197 if (isset($this->converters[$name]))
198 {
199 foreach ($this->converters[$name] as $callable)
200 {
201 $value = call_user_func($callable, $value);
202 }
203 }
204
205 return $value;
206 }
207 }
208
2
3 /*
4 * This file is part of the symfony package.
5 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11 /**
12 *
13 * @package symfony
14 * @subpackage util
15 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
16 * @version SVN: $Id: sfFillInForm.class.php 2976 2006-12-08 19:11:36Z fabien $
17 */
18 class sfFillInForm
19 {
20 protected
21 $converters = array(),
22 $skipFields = array(),
23 $types = array('text', 'checkbox', 'radio', 'hidden', 'password');
24
25 public function addConverter($callable, $fields)
26 {
27 foreach ((array) $fields as $field)
28 {
29 $this->converters[$field][] = $callable;
30 }
31 }
32
33 public function setSkipFields($fields)
34 {
35 $this->skipFields = $fields;
36 }
37
38 public function setTypes($types)
39 {
40 $this->types = $types;
41 }
42
43 public function fillInHtml($html, $formName, $formId, $values)
44 {
45 $dom = new DomDocument('1.0', sfConfig::get('sf_charset', 'UTF-8'));
46 @$dom->loadHTML($html);
47
48 $dom = $this->fillInDom($dom, $formName, $formId, $values);
49
50 return $dom->saveHTML();
51 }
52
53 public function fillInXml($xml, $formName, $formId, $values)
54 {
55 $dom = new DomDocument('1.0', sfConfig::get('sf_charset', 'UTF-8'));
56 @$dom->loadXML($xml);
57
58 $dom = $this->fillInDom($dom, $formName, $formId, $values);
59
60 return $dom->saveXML();
61 }
62
63 public function fillInDom($dom, $formName, $formId, $values)
64 {
65 $xpath = new DomXPath($dom);
66
67 $query = 'descendant::input[@name and (not(@type)';
68 foreach ($this->types as $type)
69 {
70 $query .= ' or @type="'.$type.'"';
71 }
72 $query .= ')] | descendant::textarea[@name] | descendant::select[@name]';
73
74 // find our form
75 if ($formName)
76 {
77 $xpath_query = '//form[@name="'.$formName.'"]';
78 }
79 elseif ($formId)
80 {
81 $xpath_query = '//form[@id="'.$formId.'"]';
82 }
83 else
84 {
85 $xpath_query = '//form';
86 }
87
88 $form = $xpath->query($xpath_query)->item(0);
89 if (!$form)
90 {
91 if (!$formName && !$formId)
92 {
93 throw new sfException('No form found in this page');
94 }
95 else
96 {
97 throw new sfException(sprintf('The form "%s" cannot be found', $formName ? $formName : $formId));
98 }
99 }
100
101 foreach ($xpath->query($query, $form) as $element)
102 {
103 $name = (string) $element->getAttribute('name');
104 $value = (string) $element->getAttribute('value');
105 $type = (string) $element->getAttribute('type');
106
107 // skip fields
108 if (!$this->hasValue($values, $name) || in_array($name, $this->skipFields))
109 {
110 continue;
111 }
112
113 if ($element->nodeName == 'input')
114 {
115 if ($type == 'checkbox' || $type == 'radio')
116 {
117 // checkbox and radio
118 $element->removeAttribute('checked');
119 if ($this->hasValue($values, $name) && ($this->getValue($values, $name) == $value || !$element->hasAttribute('value')))
120 {
121 $element->setAttribute('checked', 'checked');
122 }
123 }
124 else
125 {
126 // text input
127 $element->removeAttribute('value');
128 if ($this->hasValue($values, $name))
129 {
130 $element->setAttribute('value', $this->escapeValue($this->getValue($values, $name), $name));
131 }
132 }
133 }
134 else if ($element->nodeName == 'textarea')
135 {
136 $el = $element->cloneNode(false);
137 $el->appendChild($dom->createTextNode($this->escapeValue($this->getValue($values, $name), $name)));
138 $element->parentNode->replaceChild($el, $element);
139 }
140 else if ($element->nodeName == 'select')
141 {
142 // select
143 $value = $this->getValue($values, $name);
144 $multiple = $element->hasAttribute('multiple');
145 foreach ($xpath->query('descendant::option', $element) as $option)
146 {
147 $option->removeAttribute('selected');
148 if ($multiple && is_array($value))
149 {
150 if (in_array($option->getAttribute('value'), $value))
151 {
152 $option->setAttribute('selected', 'selected');
153 }
154 }
155 else if ($value == $option->getAttribute('value'))
156 {
157 $option->setAttribute('selected', 'selected');
158 }
159 }
160 }
161 }
162
163 return $dom;
164 }
165
166 protected function hasValue($values, $name)
167 {
168 if (array_key_exists($name, $values))
169 {
170 return true;
171 }
172
173 return null !== sfToolkit::getArrayValueForPath($values, $name);
174 }
175
176 protected function getValue($values, $name)
177 {
178 if (array_key_exists($name, $values))
179 {
180 return $values[$name];
181 }
182
183 return sfToolkit::getArrayValueForPath($values, $name);
184 }
185
186 protected function escapeValue($value, $name)
187 {
188 if (function_exists('iconv') && strtolower(sfConfig::get('sf_charset')) != 'utf-8')
189 {
190 $new_value = iconv(sfConfig::get('sf_charset'), 'UTF-8', $value);
191 if (false !== $new_value)
192 {
193 $value = $new_value;
194 }
195 }
196
197 if (isset($this->converters[$name]))
198 {
199 foreach ($this->converters[$name] as $callable)
200 {
201 $value = call_user_func($callable, $value);
202 }
203 }
204
205 return $value;
206 }
207 }
208