1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\DependencyInjection\Extension;
13
14use Symfony\Component\DependencyInjection\Container;
15use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
16use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
17use Symfony\Component\Config\Resource\FileResource;
18use Symfony\Component\DependencyInjection\ContainerBuilder;
19use Symfony\Component\Config\Definition\Processor;
20use Symfony\Component\Config\Definition\ConfigurationInterface;
21
22/**
23 * Provides useful features shared by many extensions.
24 *
25 * @author Fabien Potencier <fabien@symfony.com>
26 */
27abstract class Extension implements ExtensionInterface, ConfigurationExtensionInterface
28{
29    /**
30     * Returns the base path for the XSD files.
31     *
32     * @return string The XSD base path
33     */
34    public function getXsdValidationBasePath()
35    {
36        return false;
37    }
38
39    /**
40     * Returns the namespace to be used for this extension (XML namespace).
41     *
42     * @return string The XML namespace
43     */
44    public function getNamespace()
45    {
46        return 'http://example.org/schema/dic/'.$this->getAlias();
47    }
48
49    /**
50     * Returns the recommended alias to use in XML.
51     *
52     * This alias is also the mandatory prefix to use when using YAML.
53     *
54     * This convention is to remove the "Extension" postfix from the class
55     * name and then lowercase and underscore the result. So:
56     *
57     *     AcmeHelloExtension
58     *
59     * becomes
60     *
61     *     acme_hello
62     *
63     * This can be overridden in a sub-class to specify the alias manually.
64     *
65     * @return string The alias
66     *
67     * @throws BadMethodCallException When the extension name does not follow conventions
68     */
69    public function getAlias()
70    {
71        $className = get_class($this);
72        if (substr($className, -9) != 'Extension') {
73            throw new BadMethodCallException('This extension does not follow the naming convention; you must overwrite the getAlias() method.');
74        }
75        $classBaseName = substr(strrchr($className, '\\'), 1, -9);
76
77        return Container::underscore($classBaseName);
78    }
79
80    /**
81     * {@inheritdoc}
82     */
83    public function getConfiguration(array $config, ContainerBuilder $container)
84    {
85        $reflected = new \ReflectionClass($this);
86        $namespace = $reflected->getNamespaceName();
87
88        $class = $namespace.'\\Configuration';
89        if (class_exists($class)) {
90            $r = new \ReflectionClass($class);
91            $container->addResource(new FileResource($r->getFileName()));
92
93            if (!method_exists($class, '__construct')) {
94                $configuration = new $class();
95
96                return $configuration;
97            }
98        }
99    }
100
101    final protected function processConfiguration(ConfigurationInterface $configuration, array $configs)
102    {
103        $processor = new Processor();
104
105        return $processor->processConfiguration($configuration, $configs);
106    }
107
108    /**
109     * @param ContainerBuilder $container
110     * @param array            $config
111     *
112     * @return bool Whether the configuration is enabled
113     *
114     * @throws InvalidArgumentException When the config is not enableable
115     */
116    protected function isConfigEnabled(ContainerBuilder $container, array $config)
117    {
118        if (!array_key_exists('enabled', $config)) {
119            throw new InvalidArgumentException("The config array has no 'enabled' key.");
120        }
121
122        return (bool) $container->getParameterBag()->resolveValue($config['enabled']);
123    }
124}
125