| Code Coverage
| Classes and Traits | Functions and Methods | Lines
Total |  | 0.00% | 0 / 1 |  | 71.43% | 10 / 14 | CRAP |  | 93.07% | 94 / 101
LoggerConfigurationAdapterXML |  | 0.00% | 0 / 1 |  | 71.43% | 10 / 14 | 41.56 |  | 93.07% | 94 / 101
convert($url) |  | 100.00% | 1 / 1 | 6 |  | 100.00% | 18 / 18
loadXML($url) |  | 100.00% | 1 / 1 | 4 |  | 100.00% | 14 / 14
parseConfiguration(SimpleXMLElement $xml) |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 5 / 5
parseAppender(SimpleXMLElement $node) |  | 0.00% | 0 / 1 | 6.04 |  | 90.00% | 18 / 20
parseLayout(SimpleXMLElement $node, $appenderName) |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 6 / 6
parseParameters($paramsNode) |  | 0.00% | 0 / 1 | 3.21 |  | 71.43% | 5 / 7
parseRootLogger(SimpleXMLElement $node) |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 3 / 3
parseLogger(SimpleXMLElement $node) |  | 0.00% | 0 / 1 | 5.15 |  | 81.82% | 9 / 11
parseAppenderReferences(SimpleXMLElement $node) |  | 100.00% | 1 / 1 | 3 |  | 100.00% | 6 / 6
parseFilter($filterNode) |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 4 / 4
parseRenderer(SimpleXMLElement $node) |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 2 / 2
parseDefaultRenderer(SimpleXMLElement $node) |  | 0.00% | 0 / 1 | 2.15 |  | 66.67% | 2 / 3
getAttributeValue(SimpleXMLElement $node, $name) |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 1 / 1
warn($message) |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 1 / 1

1 | <?php
2 | /**
3 | * Licensed to the Apache Software Foundation (ASF) under one or more
4 | * contributor license agreements. See the NOTICE file distributed with
5 | * this work for additional information regarding copyright ownership.
6 | * The ASF licenses this file to You under the Apache License, Version 2.0
7 | * (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @package log4php
19 | */
20 |
21 | /**
22 | * Converts XML configuration files to a PHP array.
23 | *
24 | * @package log4php
25 | * @subpackage configurators
26 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
27 | * @version $Revision: 1394956 $
28 | * @since 2.2
29 | */
30 | class LoggerConfigurationAdapterXML implements LoggerConfigurationAdapter
31 | {
32 | /** Path to the XML schema used for validation. */
33 | const SCHEMA_PATH = '/../xml/log4php.xsd';
34 |
35 | private $config = array(
36 | 'appenders' => array(),
37 | 'loggers' => array(),
38 | 'renderers' => array(),
39 | );
40 |
41 | public function convert($url) {
42 | $xml = $this->loadXML($url);
43 |
44 | $this->parseConfiguration($xml);
45 |
46 | // Parse the <root> node
47 | if (isset($xml->root)) {
48 | $this->parseRootLogger($xml->root);
49 | }
50 |
51 | // Process <logger> nodes
52 | foreach($xml->logger as $logger) {
53 | $this->parseLogger($logger);
54 | }
55 |
56 | // Process <appender> nodes
57 | foreach($xml->appender as $appender) {
58 | $this->parseAppender($appender);
59 | }
60 |
61 | // Process <renderer> nodes
62 | foreach($xml->renderer as $rendererNode) {
63 | $this->parseRenderer($rendererNode);
64 | }
65 |
66 | // Process <defaultRenderer> node
67 | foreach($xml->defaultRenderer as $rendererNode) {
68 | $this->parseDefaultRenderer($rendererNode);
69 | }
70 |
71 | return $this->config;
72 | }
73 |
74 | /**
75 | * Loads and validates the XML.
76 | * @param string $url Input XML.
77 | */
78 | private function loadXML($url) {
79 | if (!file_exists($url)) {
80 | throw new LoggerException("File [$url] does not exist.");
81 | }
82 |
83 | libxml_clear_errors();
84 | $oldValue = libxml_use_internal_errors(true);
85 |
86 | // Load XML
87 | $xml = @simplexml_load_file($url);
88 | if ($xml === false) {
89 |
90 | $errorStr = "";
91 | foreach(libxml_get_errors() as $error) {
92 | $errorStr .= $error->message;
93 | }
94 |
95 | throw new LoggerException("Error loading configuration file: " . trim($errorStr));
96 | }
97 |
98 | libxml_clear_errors();
99 | libxml_use_internal_errors($oldValue);
100 |
101 | return $xml;
102 | }
103 |
104 | /**
105 | * Parses the <configuration> node.
106 | */
107 | private function parseConfiguration(SimpleXMLElement $xml) {
108 | $attributes = $xml->attributes();
109 | if (isset($attributes['threshold'])) {
110 | $this->config['threshold'] = (string) $attributes['threshold'];
111 | }
112 | }
113 |
114 | /** Parses an <appender> node. */
115 | private function parseAppender(SimpleXMLElement $node) {
116 | $name = $this->getAttributeValue($node, 'name');
117 | if (empty($name)) {
118 | $this->warn("An <appender> node is missing the required 'name' attribute. Skipping appender definition.");
119 | return;
120 | }
121 |
122 | $appender = array();
123 | $appender['class'] = $this->getAttributeValue($node, 'class');
124 |
125 | if (isset($node['threshold'])) {
126 | $appender['threshold'] = $this->getAttributeValue($node, 'threshold');
127 | }
128 |
129 | if (isset($node->layout)) {
130 | $appender['layout']= $this->parseLayout($node->layout, $name);
131 | }
132 |
133 | if (count($node->param) > 0) {
134 | $appender['params'] = $this->parseParameters($node);
135 | }
136 |
137 | foreach($node->filter as $filterNode) {
138 | $appender['filters'][] = $this->parseFilter($filterNode);
139 | }
140 |
141 | $this->config['appenders'][$name] = $appender;
142 | }
143 |
144 | /** Parses a <layout> node. */
145 | private function parseLayout(SimpleXMLElement $node, $appenderName) {
146 | $layout = array();
147 | $layout['class'] = $this->getAttributeValue($node, 'class');
148 |
149 | if (count($node->param) > 0) {
150 | $layout['params'] = $this->parseParameters($node);
151 | }
152 |
153 | return $layout;
154 | }
155 | /** Parses any <param> child nodes returning them in an array. */
156 | private function parseParameters($paramsNode) {
157 | $params = array();
158 |
159 | foreach($paramsNode->param as $paramNode) {
160 | if (empty($paramNode['name'])) {
161 | $this->warn("A <param> node is missing the required 'name' attribute. Skipping parameter.");
162 | continue;
163 | }
164 |
165 | $name = $this->getAttributeValue($paramNode, 'name');
166 | $value = $this->getAttributeValue($paramNode, 'value');
167 |
168 | $params[$name] = $value;
169 | }
170 |
171 | return $params;
172 | }
173 |
174 | /** Parses a <root> node. */
175 | private function parseRootLogger(SimpleXMLElement $node) {
176 | $logger = array();
177 |
178 | if (isset($node->level)) {
179 | $logger['level'] = $this->getAttributeValue($node->level, 'value');
180 | }
181 |
182 | $logger['appenders'] = $this->parseAppenderReferences($node);
183 |
184 | $this->config['rootLogger'] = $logger;
185 | }
186 |
187 | /** Parses a <logger> node. */
188 | private function parseLogger(SimpleXMLElement $node) {
189 | $logger = array();
190 |
191 | $name = $this->getAttributeValue($node, 'name');
192 | if (empty($name)) {
193 | $this->warn("A <logger> node is missing the required 'name' attribute. Skipping logger definition.");
194 | return;
195 | }
196 |
197 | if (isset($node->level)) {
198 | $logger['level'] = $this->getAttributeValue($node->level, 'value');
199 | }
200 |
201 | if (isset($node['additivity'])) {
202 | $logger['additivity'] = $this->getAttributeValue($node, 'additivity');
203 | }
204 |
205 | $logger['appenders'] = $this->parseAppenderReferences($node);
206 |
207 | // Check for duplicate loggers
208 | if (isset($this->config['loggers'][$name])) {
209 | $this->warn("Duplicate logger definition [$name]. Overwriting.");
210 | }
211 |
212 | $this->config['loggers'][$name] = $logger;
213 | }
214 |
215 | /**
216 | * Parses a <logger> node for appender references and returns them in an array.
217 | *
218 | * Previous versions supported appender-ref, as well as appender_ref so both
219 | * are parsed for backward compatibility.
220 | */
221 | private function parseAppenderReferences(SimpleXMLElement $node) {
222 | $refs = array();
223 | foreach($node->appender_ref as $ref) {
224 | $refs[] = $this->getAttributeValue($ref, 'ref');
225 | }
226 |
227 | foreach($node->{'appender-ref'} as $ref) {
228 | $refs[] = $this->getAttributeValue($ref, 'ref');
229 | }
230 |
231 | return $refs;
232 | }
233 |
234 | /** Parses a <filter> node. */
235 | private function parseFilter($filterNode) {
236 | $filter = array();
237 | $filter['class'] = $this->getAttributeValue($filterNode, 'class');
238 |
239 | if (count($filterNode->param) > 0) {
240 | $filter['params'] = $this->parseParameters($filterNode);
241 | }
242 |
243 | return $filter;
244 | }
245 |
246 | /** Parses a <renderer> node. */
247 | private function parseRenderer(SimpleXMLElement $node) {
248 | $renderedClass = $this->getAttributeValue($node, 'renderedClass');
249 | $renderingClass = $this->getAttributeValue($node, 'renderingClass');
250 |
251 | $this->config['renderers'][] = compact('renderedClass', 'renderingClass');
252 | }
253 |
254 | /** Parses a <defaultRenderer> node. */
255 | private function parseDefaultRenderer(SimpleXMLElement $node) {
256 | $renderingClass = $this->getAttributeValue($node, 'renderingClass');
257 |
258 | // Warn on duplicates
259 | if(isset($this->config['defaultRenderer'])) {
260 | $this->warn("Duplicate <defaultRenderer> node. Overwriting.");
261 | }
262 |
263 | $this->config['defaultRenderer'] = $renderingClass;
264 | }
265 |
266 | // ******************************************
267 | // ** Helper methods **
268 | // ******************************************
269 |
270 | private function getAttributeValue(SimpleXMLElement $node, $name) {
271 | return isset($node[$name]) ? (string) $node[$name] : null;
272 | }
273 |
274 | private function warn($message) {
275 | trigger_error("log4php: " . $message, E_USER_WARNING);
276 | }
277 | }
278 |