1: <?php
  2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19: 
 20: 
 21:  22:  23:  24:  25:  26:  27:  28:  29:  30: 
 31: class LoggerConfiguratorDefault implements LoggerConfigurator
 32: {
 33:     
 34:     const FORMAT_XML = 'xml';
 35:     
 36:     
 37:     const FORMAT_PHP = 'php';
 38:     
 39:     
 40:     const FORMAT_INI = 'ini';
 41: 
 42:     
 43:     private $adapters = array(
 44:         self::FORMAT_XML => 'LoggerConfigurationAdapterXML',
 45:         self::FORMAT_INI => 'LoggerConfigurationAdapterINI',
 46:         self::FORMAT_PHP => 'LoggerConfigurationAdapterPHP',
 47:     );
 48:     
 49:     
 50:     private static $defaultConfiguration = array(
 51:         'threshold' => 'ALL',
 52:         'rootLogger' => array(
 53:             'level' => 'DEBUG',
 54:             'appenders' => array('default'),
 55:         ),
 56:         'appenders' => array(
 57:             'default' => array(
 58:                 'class' => 'LoggerAppenderEcho'
 59:             ),
 60:         ),
 61:     );
 62:     
 63:     
 64:     private $appenders = array();
 65:     
 66:      67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81: 
 82:     public function configure(LoggerHierarchy $hierarchy, $input = null) {
 83:         $config = $this->parse($input);
 84:         $this->doConfigure($hierarchy, $config);
 85:     }
 86:     
 87:      88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 
100:     public function parse($input) {
101:         
102:         if (!isset($input)) {
103:             $config = self::$defaultConfiguration;
104:         }
105:         
106:         
107:         else if (is_array($input)) {
108:             $config = $input;
109:         }
110:         
111:         
112:         else if (is_string($input)) {
113:             try {
114:                 $config = $this->parseFile($input);
115:             } catch (LoggerException $e) {
116:                 $this->warn("Configuration failed. " . $e->getMessage() . " Using default configuration.");
117:                 $config = self::$defaultConfiguration;
118:             }
119:         }
120:         
121:         
122:         else {
123:             $this->warn("Invalid configuration param given. Reverting to default configuration.");
124:             $config = self::$defaultConfiguration;
125:         }
126:         
127:         return $config;
128:     }
129: 
130:     131: 132: 133: 
134:     public static function getDefaultConfiguration() {
135:         return self::$defaultConfiguration;
136:     } 
137:     
138:     139: 140: 141: 142: 143: 144: 145: 146: 147: 
148:     private function parseFile($url) {
149:         
150:         if (!file_exists($url)) {
151:             throw new LoggerException("File not found at [$url].");
152:         }
153:         
154:         $type = $this->getConfigType($url);
155:         $adapterClass = $this->adapters[$type];
156: 
157:         $adapter = new $adapterClass();
158:         return $adapter->convert($url);
159:     }
160:     
161:     
162:     private function getConfigType($url) {
163:         $info = pathinfo($url);
164:         $ext = strtolower($info['extension']);
165:         
166:         switch($ext) {
167:             case 'xml':
168:                 return self::FORMAT_XML;
169:             
170:             case 'ini':
171:             case 'properties':
172:                 return self::FORMAT_INI;
173:             
174:             case 'php':
175:                 return self::FORMAT_PHP;
176:                 
177:             default:
178:                 throw new LoggerException("Unsupported configuration file extension: $ext");
179:         }
180:     }
181:     
182:     183: 184: 185: 186: 187: 
188:     private function doConfigure(LoggerHierarchy $hierarchy, $config) {
189:         if (isset($config['threshold'])) {
190:             $threshold = LoggerLevel::toLevel($config['threshold']);
191:             if (isset($threshold)) {
192:                 $hierarchy->setThreshold($threshold);
193:             } else {
194:                 $this->warn("Invalid threshold value [{$config['threshold']}] specified. Ignoring threshold definition.");
195:             }
196:         }
197:         
198:         
199:         if (isset($config['appenders']) && is_array($config['appenders'])) {
200:             foreach($config['appenders'] as $name => $appenderConfig) {
201:                 $this->configureAppender($name, $appenderConfig);
202:             }
203:         }
204:         
205:         
206:         if (isset($config['rootLogger'])) {
207:             $this->configureRootLogger($hierarchy, $config['rootLogger']);
208:         }
209:         
210:         
211:         if (isset($config['loggers']) && is_array($config['loggers'])) {
212:             foreach($config['loggers'] as $loggerName => $loggerConfig) {
213:                 $this->configureOtherLogger($hierarchy, $loggerName, $loggerConfig);
214:             }
215:         }
216: 
217:         
218:         if (isset($config['renderers']) && is_array($config['renderers'])) {
219:             foreach($config['renderers'] as $rendererConfig) {
220:                 $this->configureRenderer($hierarchy, $rendererConfig);
221:             }
222:         }
223:         
224:         if (isset($config['defaultRenderer'])) {
225:             $this->configureDefaultRenderer($hierarchy, $config['defaultRenderer']);
226:         }
227:     }
228:     
229:     private function configureRenderer(LoggerHierarchy $hierarchy, $config) {
230:         if (empty($config['renderingClass'])) {
231:             $this->warn("Rendering class not specified. Skipping renderer definition.");
232:             return;
233:         }
234:         
235:         if (empty($config['renderedClass'])) {
236:             $this->warn("Rendered class not specified. Skipping renderer definition.");
237:             return;
238:         }
239:         
240:         
241:         $hierarchy->getRendererMap()->addRenderer($config['renderedClass'], $config['renderingClass']);
242:     }
243:     
244:     private function configureDefaultRenderer(LoggerHierarchy $hierarchy, $class) {
245:         if (empty($class)) {
246:             $this->warn("Rendering class not specified. Skipping default renderer definition.");
247:             return;
248:         }
249:         
250:         
251:         $hierarchy->getRendererMap()->setDefaultRenderer($class);
252:     }
253:     
254:     255: 256: 257: 258: 259: 
260:     private function configureAppender($name, $config) {
261: 
262:         
263:         if (!is_array($config)) {
264:             $type = gettype($config);
265:             $this->warn("Invalid configuration provided for appender [$name]. Expected an array, found <$type>. Skipping appender definition.");
266:             return;
267:         }
268:         
269:         
270:         $class = $config['class'];
271:         if (empty($class)) {
272:             $this->warn("No class given for appender [$name]. Skipping appender definition.");
273:             return;
274:         }
275:         if (!class_exists($class)) {
276:             $this->warn("Invalid class [$class] given for appender [$name]. Class does not exist. Skipping appender definition.");
277:             return;
278:         }
279:         
280:         
281:         $appender = new $class($name);
282:         if (!($appender instanceof LoggerAppender)) {
283:             $this->warn("Invalid class [$class] given for appender [$name]. Not a valid LoggerAppender class. Skipping appender definition.");
284:             return;
285:         }
286:         
287:         
288:         if (isset($config['threshold'])) {
289:             $threshold = LoggerLevel::toLevel($config['threshold']);
290:             if ($threshold instanceof LoggerLevel) {
291:                 $appender->setThreshold($threshold);
292:             } else {
293:                 $this->warn("Invalid threshold value [{$config['threshold']}] specified for appender [$name]. Ignoring threshold definition.");
294:             }
295:         }
296:         
297:         
298:         if ($appender->requiresLayout() && isset($config['layout'])) {
299:             $this->createAppenderLayout($appender, $config['layout']);
300:         }
301:         
302:         
303:         if (isset($config['filters']) && is_array($config['filters'])) {
304:             foreach($config['filters'] as $filterConfig) {
305:                 $this->createAppenderFilter($appender, $filterConfig);
306:             }
307:         }
308:         
309:         
310:         if (isset($config['params'])) {
311:             $this->setOptions($appender, $config['params']);
312:         }
313: 
314:         
315:         $appender->activateOptions();
316:         $this->appenders[$name] = $appender;
317:     }
318:     
319:     320: 321: 322: 323: 
324:     private function createAppenderLayout(LoggerAppender $appender, $config) {
325:         $name = $appender->getName();
326:         $class = $config['class'];
327:         if (empty($class)) {
328:             $this->warn("Layout class not specified for appender [$name]. Reverting to default layout.");
329:             return;
330:         }
331:         if (!class_exists($class)) {
332:             $this->warn("Nonexistant layout class [$class] specified for appender [$name]. Reverting to default layout.");
333:             return;
334:         }
335:         
336:         $layout = new $class();
337:         if (!($layout instanceof LoggerLayout)) {
338:             $this->warn("Invalid layout class [$class] sepcified for appender [$name]. Reverting to default layout.");
339:             return;
340:         }
341:         
342:         if (isset($config['params'])) {
343:             $this->setOptions($layout, $config['params']);
344:         }
345:         
346:         $layout->activateOptions();
347:         $appender->setLayout($layout);
348:     }
349:     
350:     351: 352: 353: 354: 355: 
356:     private function createAppenderFilter(LoggerAppender $appender, $config) {
357:         $name = $appender->getName();
358:         $class = $config['class'];
359:         if (!class_exists($class)) {
360:             $this->warn("Nonexistant filter class [$class] specified on appender [$name]. Skipping filter definition.");
361:             return;
362:         }
363:     
364:         $filter = new $class();
365:         if (!($filter instanceof LoggerFilter)) {
366:             $this->warn("Invalid filter class [$class] sepcified on appender [$name]. Skipping filter definition.");
367:             return;
368:         }
369:     
370:         if (isset($config['params'])) {
371:             $this->setOptions($filter, $config['params']);
372:         }
373:     
374:         $filter->activateOptions();
375:         $appender->addFilter($filter);
376:     }
377:     
378:     379: 380: 381: 
382:     private function configureRootLogger(LoggerHierarchy $hierarchy, $config) {
383:         $logger = $hierarchy->getRootLogger();
384:         $this->configureLogger($logger, $config);
385:     }
386: 
387:     388: 389: 390: 
391:     private function configureOtherLogger(LoggerHierarchy $hierarchy, $name, $config) {
392:         
393:         $logger = $hierarchy->getLogger($name);
394:         $this->configureLogger($logger, $config);
395:     }
396:     
397:     398: 399: 400: 401: 402: 
403:     private function configureLogger(Logger $logger, $config) {
404:         $loggerName = $logger->getName();
405:         
406:         
407:         if (isset($config['level'])) {
408:             $level = LoggerLevel::toLevel($config['level']);
409:             if (isset($level)) {
410:                 $logger->setLevel($level);
411:             } else {
412:                 $this->warn("Invalid level value [{$config['level']}] specified for logger [$loggerName]. Ignoring level definition.");
413:             }
414:         }
415:         
416:         
417:         if (isset($config['appenders'])) {
418:             foreach($config['appenders'] as $appenderName) {
419:                 if (isset($this->appenders[$appenderName])) {
420:                     $logger->addAppender($this->appenders[$appenderName]);
421:                 } else {
422:                     $this->warn("Nonexistnant appender [$appenderName] linked to logger [$loggerName].");
423:                 }
424:             }
425:         }
426:         
427:         
428:         if (isset($config['additivity'])) {
429:             try {
430:                 $additivity = LoggerOptionConverter::toBooleanEx($config['additivity'], null);
431:                 $logger->setAdditivity($additivity);
432:             } catch (Exception $ex) {
433:                 $this->warn("Invalid additivity value [{$config['additivity']}] specified for logger [$loggerName]. Ignoring additivity setting.");
434:             }
435:         }
436:     }
437: 
438:     439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 
461:     private function setOptions($object, $options) {
462:         foreach($options as $name => $value) {
463:             $setter = "set$name";
464:             if (method_exists($object, $setter)) {
465:                 $object->$setter($value);
466:             } else {
467:                 $class = get_class($object);
468:                 $this->warn("Nonexistant option [$name] specified on [$class]. Skipping.");
469:             }
470:         }
471:     }
472:     
473:     
474:     private function warn($message) {
475:         trigger_error("log4php: $message", E_USER_WARNING);
476:     }
477: }
478: