diff --git a/core/lib/Thelia/Core/Bundle/TheliaBundle.php b/core/lib/Thelia/Core/Bundle/TheliaBundle.php
index 50d542efc..507d54453 100644
--- a/core/lib/Thelia/Core/Bundle/TheliaBundle.php
+++ b/core/lib/Thelia/Core/Bundle/TheliaBundle.php
@@ -27,6 +27,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Scope;
+use Thelia\Core\DependencyInjection\Compiler\RegisterListenersPass;
+
/**
* First Bundle use in Thelia
* It initialize dependency injection container.
@@ -49,76 +51,10 @@ class TheliaBundle extends Bundle
public function build(ContainerBuilder $container)
{
- $container->addScope( new Scope('request'));
+ parent::build($container);
- $container->register('request', 'Symfony\Component\HttpFoundation\Request')
- ->setSynthetic(true);
-
- $container->register('controller.default','Thelia\Controller\DefaultController');
- $container->register('matcher.default','Thelia\Routing\Matcher\DefaultMatcher')
- ->addArgument(new Reference('controller.default'));
-
- $container->register('matcher.action', 'Thelia\Routing\Matcher\ActionMatcher');
-
- $container->register('matcher','Thelia\Routing\TheliaMatcherCollection')
- ->addMethodCall('add', array(new Reference('matcher.default'), -255))
- ->addMethodCall('add', array(new Reference('matcher.action'), -200))
- //->addMethodCall('add','a matcher class (instance or class name)
-
- ;
-
- $container->register('resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver');
-
-
- $container->register('parser','Thelia\Core\Template\Parser')
- ->addArgument(new Reference('service_container'))
- ;
- /**
- * RouterListener implements EventSubscriberInterface and listen for kernel.request event
- */
- $container->register('listener.router', 'Symfony\Component\HttpKernel\EventListener\RouterListener')
- ->addArgument(new Reference('matcher'))
- ;
-
- /**
- * @TODO add an other listener on kernel.request for checking some params Like check if User is log in, set the language and other.
- *
- * $container->register()
- *
- *
- * $container->register('listener.request', 'Thelia\Core\EventListener\RequestListener')
- * ->addArgument(new Reference('');
- * ;
- */
-
- $container->register('thelia.listener.view','Thelia\Core\EventListener\ViewListener')
- ->addArgument(new Reference('service_container'))
- ;
-
-
-
- $container->register('dispatcher','Symfony\Component\EventDispatcher\EventDispatcher')
- ->addArgument(new Reference('service_container'))
- ->addMethodCall('addSubscriber', array(new Reference('listener.router')))
- ->addMethodCall('addSubscriber', array(new Reference('thelia.listener.view')))
- ;
-
-
- // TODO : save listener from plugins
-
- $container->getDefinition('matcher.action')->addMethodCall("setDispatcher", array(new Reference('dispatcher')));
-
- $container->register('http_kernel','Thelia\Core\TheliaHttpKernel')
- ->addArgument(new Reference('dispatcher'))
- ->addArgument(new Reference('service_container'))
- ->addArgument(new Reference('resolver'))
- ;
-
- // DEFINE DEFAULT PARAMETER LIKE
-
- /**
- * @TODO learn about container compilation
- */
+ $container->addScope(new Scope('request'));
+ $container->addCompilerPass(new RegisterListenersPass());
}
}
diff --git a/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterListenersPass.php b/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterListenersPass.php
new file mode 100644
index 000000000..881ddaceb
--- /dev/null
+++ b/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterListenersPass.php
@@ -0,0 +1,72 @@
+. */
+/* */
+/*************************************************************************************/
+
+namespace Thelia\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+
+class RegisterListenersPass implements CompilerPassInterface
+{
+ public function process(ContainerBuilder $container)
+ {
+ if (!$container->hasDefinition('event_dispatcher')) {
+ return;
+ }
+
+ $definition = $container->getDefinition('event_dispatcher');
+
+ foreach ($container->findTaggedServiceIds('kernel.event_listener') as $id => $events) {
+ foreach ($events as $event) {
+ $priority = isset($event['priority']) ? $event['priority'] : 0;
+
+ if (!isset($event['event'])) {
+ throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "kernel.event_listener" tags.', $id));
+ }
+
+ if (!isset($event['method'])) {
+ $event['method'] = 'on'.preg_replace(array(
+ '/(?<=\b)[a-z]/ie',
+ '/[^a-z0-9]/i'
+ ), array('strtoupper("\\0")', ''), $event['event']);
+ }
+
+ $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
+ }
+ }
+
+ foreach ($container->findTaggedServiceIds('kernel.event_subscriber') as $id => $attributes) {
+ // We must assume that the class value has been correctly filled, even if the service is created by a factory
+ $class = $container->getDefinition($id)->getClass();
+
+ $refClass = new \ReflectionClass($class);
+ $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
+ if (!$refClass->implementsInterface($interface)) {
+ throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
+ }
+
+ $definition->addMethodCall('addSubscriberService', array($id, $class));
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/lib/Thelia/Core/DependencyInjection/Loader/XmlFileLoader.php b/core/lib/Thelia/Core/DependencyInjection/Loader/XmlFileLoader.php
new file mode 100644
index 000000000..39e18a6ab
--- /dev/null
+++ b/core/lib/Thelia/Core/DependencyInjection/Loader/XmlFileLoader.php
@@ -0,0 +1,314 @@
+. */
+/* */
+/*************************************************************************************/
+
+namespace Thelia\Core\DependencyInjection\Loader;
+
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader as XmlLoader;
+use Symfony\Component\Config\Util\XmlUtils;
+use Symfony\Component\DependencyInjection\DefinitionDecorator;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Alias;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\SimpleXMLElement;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\DependencyInjection\Loader\FileLoader;
+
+class XmlFileLoader extends FileLoader
+{
+ /**
+ * Loads an XML file.
+ *
+ * @param mixed $file The resource
+ * @param string $type The resource type
+ */
+ public function load($file, $type = null)
+ {
+ $path = $this->locator->locate($file);
+
+ $xml = $this->parseFile($path);
+ $xml->registerXPathNamespace('config', 'http://thelia.net/schema/dic/config');
+
+ $this->container->addResource(new FileResource($path));
+
+ $this->parseDefinitions($xml, $path);
+
+ $this->parseLoops($xml);
+
+ $this->parseFilters($xml);
+
+ $this->parseBaseParams($xml);
+
+ $this->parseTestLoops($xml);
+ }
+
+ protected function parseLoops(SimpleXMLElement $xml)
+ {
+ if (false === $loops = $xml->xpath('//config:loops/config:loop')) {
+ return;
+ }
+ try {
+ $loopConfig = $this->container->getParameter("Tpex.loop");
+ } catch (\Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException $e) {
+ $loopConfig = array();
+ }
+
+ foreach ($loops as $loop) {
+ $loopConfig[$loop->getAttributeAsPhp("name")] = $loop->getAttributeAsPhp("class");
+ }
+
+ $this->container->setParameter("Tpex.loop", $loopConfig);
+ }
+
+ protected function parseFilters(SimpleXMLElement $xml)
+ {
+ if (false === $filters = $xml->xpath('//config:filters/config:filter')) {
+ return;
+ }
+ try {
+ $filterConfig = $this->container->getParameter("Tpex.filter");
+ } catch (\Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException $e) {
+ $filterConfig = array();
+ }
+
+ foreach ($filters as $filter) {
+ $filterConfig[$filter->getAttributeAsPhp("name")] = $filter->getAttributeAsPhp("class");
+ }
+
+ $this->container->setParameter("Tpex.filter", $filterConfig);
+ }
+
+ protected function parseBaseParams(SimpleXMLElement $xml)
+ {
+ if (false === $baseParams = $xml->xpath('//config:baseParams/config:baseParam')) {
+ return;
+ }
+ try {
+ $baseParamConfig = $this->container->getParameter("Tpex.baseParam");
+ } catch (\Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException $e) {
+ $baseParamConfig = array();
+ }
+
+ foreach ($baseParams as $baseParam) {
+ $baseParamConfig[$baseParam->getAttributeAsPhp("name")] = $baseParam->getAttributeAsPhp("class");
+ }
+
+ $this->container->setParameter("Tpex.baseParam", $baseParamConfig);
+ }
+
+ protected function parseTestLoops(SimpleXMLElement $xml)
+ {
+ if (false === $testLoops = $xml->xpath('//config:testLoops/config:testLoop')) {
+ return;
+ }
+ try {
+ $baseParamConfig = $this->container->getParameter("Tpex.baseParam");
+ } catch (\Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException $e) {
+ $baseParamConfig = array();
+ }
+
+ foreach ($testLoops as $testLoop) {
+ $baseParamConfig[$testLoop->getAttributeAsPhp("name")] = $testLoop->getAttributeAsPhp("class");
+ }
+
+ $this->container->setParameter("Tpex.testLoop", $baseParamConfig);
+ }
+
+ /**
+ * Parses multiple definitions
+ *
+ * @param SimpleXMLElement $xml
+ * @param string $file
+ */
+ protected function parseDefinitions(SimpleXMLElement $xml, $file)
+ {
+ if (false === $services = $xml->xpath('//config:services/config:service')) {
+ return;
+ }
+ foreach ($services as $service) {
+ $this->parseDefinition((string) $service['id'], $service, $file);
+ }
+ }
+
+ /**
+ * Parses an individual Definition
+ *
+ * @param string $id
+ * @param SimpleXMLElement $service
+ * @param string $file
+ */
+ protected function parseDefinition($id, $service, $file)
+ {
+
+ if ((string) $service['alias']) {
+ $public = true;
+ if (isset($service['public'])) {
+ $public = $service->getAttributeAsPhp('public');
+ }
+ $this->container->setAlias($id, new Alias((string) $service['alias'], $public));
+
+ return;
+ }
+
+ if (isset($service['parent'])) {
+ $definition = new DefinitionDecorator((string) $service['parent']);
+ } else {
+ $definition = new Definition();
+ }
+
+ foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'abstract') as $key) {
+ if (isset($service[$key])) {
+ $method = 'set'.str_replace('-', '', $key);
+ $definition->$method((string) $service->getAttributeAsPhp($key));
+ }
+ }
+
+ if ($service->file) {
+ $definition->setFile((string) $service->file);
+ }
+
+ $definition->setArguments($service->getArgumentsAsPhp('argument'));
+ $definition->setProperties($service->getArgumentsAsPhp('property'));
+
+ if (isset($service->configurator)) {
+ if (isset($service->configurator['function'])) {
+ $definition->setConfigurator((string) $service->configurator['function']);
+ } else {
+ if (isset($service->configurator['service'])) {
+ $class = new Reference((string) $service->configurator['service'], ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
+ } else {
+ $class = (string) $service->configurator['class'];
+ }
+
+ $definition->setConfigurator(array($class, (string) $service->configurator['method']));
+ }
+ }
+
+ foreach ($service->call as $call) {
+ $definition->addMethodCall((string) $call['method'], $call->getArgumentsAsPhp('argument'));
+ }
+
+ foreach ($service->tag as $tag) {
+ $parameters = array();
+ foreach ($tag->attributes() as $name => $value) {
+ if ('name' === $name) {
+ continue;
+ }
+
+ $parameters[$name] = SimpleXMLElement::phpize($value);
+ }
+
+ $definition->addTag((string) $tag['name'], $parameters);
+ }
+
+ $this->container->setDefinition($id, $definition);
+ }
+
+ /**
+ * Parses a XML file.
+ *
+ * @param string $file Path to a file
+ *
+ * @return SimpleXMLElement
+ *
+ * @throws InvalidArgumentException When loading of XML file returns error
+ */
+ protected function parseFile($file)
+ {
+ try {
+ $dom = XmlUtils::loadFile($file, array($this, 'validateSchema'));
+ } catch (\InvalidArgumentException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return simplexml_import_dom($dom, 'Symfony\\Component\\DependencyInjection\\SimpleXMLElement');
+ }
+
+ /**
+ * Validates a documents XML schema.
+ *
+ * @param \DOMDocument $dom
+ *
+ * @return Boolean
+ *
+ * @throws RuntimeException When extension references a non-existent XSD file
+ */
+ public function validateSchema(\DOMDocument $dom)
+ {
+ $schemaLocations = array('http://thelia.net/schema/dic/config' => str_replace('\\', '/',__DIR__.'/schema/dic/config/thelia-1.0.xsd'));
+
+ $tmpfiles = array();
+ $imports = '';
+ foreach ($schemaLocations as $namespace => $location) {
+ $parts = explode('/', $location);
+ if (0 === stripos($location, 'phar://')) {
+ $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
+ if ($tmpfile) {
+ copy($location, $tmpfile);
+ $tmpfiles[] = $tmpfile;
+ $parts = explode('/', str_replace('\\', '/', $tmpfile));
+ }
+ }
+ $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
+ $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
+
+ $imports .= sprintf(' '."\n", $namespace, $location);
+ }
+
+ $source = <<
+
+
+
+$imports
+
+EOF
+ ;
+
+ $valid = @$dom->schemaValidateSource($source);
+
+ foreach ($tmpfiles as $tmpfile) {
+ @unlink($tmpfile);
+ }
+
+ return $valid;
+ }
+
+ /**
+ * Returns true if this class supports the given resource.
+ *
+ * @param mixed $resource A resource
+ * @param string $type The resource type
+ *
+ * @return Boolean true if this class supports the given resource, false otherwise
+ */
+ public function supports($resource, $type = null)
+ {
+ // TODO: Implement supports() method.
+ }
+}
\ No newline at end of file
diff --git a/core/lib/Thelia/Core/DependencyInjection/Loader/schema/dic/config/thelia-1.0.xsd b/core/lib/Thelia/Core/DependencyInjection/Loader/schema/dic/config/thelia-1.0.xsd
new file mode 100644
index 000000000..64563b0cb
--- /dev/null
+++ b/core/lib/Thelia/Core/DependencyInjection/Loader/schema/dic/config/thelia-1.0.xsd
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/lib/Thelia/Core/Template/Parser.php b/core/lib/Thelia/Core/Template/Parser.php
index 346ab2bfc..1a4d3c8be 100644
--- a/core/lib/Thelia/Core/Template/Parser.php
+++ b/core/lib/Thelia/Core/Template/Parser.php
@@ -150,7 +150,7 @@ class Parser implements ParserInterface
$tpex = new Tpex();
- $tpex->init($this->container->get("request"), $this->container->get("dispatcher"), $content, THELIA_TEMPLATE_DIR . rtrim($this->template, "/") . "/");
+ $tpex->init($this->container->get("request"), $this->container->get("event_dispatcher"), $content, THELIA_TEMPLATE_DIR . rtrim($this->template, "/") . "/");
$tpex->configure(
$this->container->getParameter("Tpex.loop"),
$this->container->getParameter("Tpex.filter"),
diff --git a/core/lib/Thelia/Core/Thelia.php b/core/lib/Thelia/Core/Thelia.php
index 08980f01d..03ff5324d 100644
--- a/core/lib/Thelia/Core/Thelia.php
+++ b/core/lib/Thelia/Core/Thelia.php
@@ -47,8 +47,9 @@ use Thelia\Core\Bundle;
use Thelia\Log\Tlog;
use Thelia\Config\DatabaseConfiguration;
use Thelia\Config\DefinePropel;
-use Thelia\Config\Dumper\TpexConfigDumper;
use Thelia\Core\TheliaContainerBuilder;
+use Thelia\Core\DependencyInjection\Loader\XmlFileLoader;
+use Symfony\Component\Config\FileLocator;
use Propel;
use PropelConfiguration;
@@ -101,106 +102,23 @@ class Thelia extends Kernel
* Initialize all plugins
*
*/
- public function loadConfiguration(ContainerBuilder $container)
+ protected function loadConfiguration(ContainerBuilder $container)
{
- /**
- * TODO :
- * - Retrieve all actives plugins
- * - load config (create a cache and use this cache
- */
-
-
- /**
- * Set all listener here.
- * Use $dispatcher->addSubscriber or addListener ?
- */
- $dispatcher = $container->get("dispatcher");
-
-
-
-
- /**
- * manage Tpex configuration here
- */
- $container = $this->generateTpexConfig($container);
-
-
-
- return $container;
-
- }
-
- protected function generateTpexConfig(ContainerBuilder $container)
- {
- $loopConfig = array();
- $filterConfig = array();
- $baseParamConfig = array();
- $loopTestConfig = array();
- $resources = array();
-
- //load master config, can be overload using modules
-
- $masterConfigFile = THELIA_ROOT . "/core/lib/Thelia/config.xml";
-
- if (file_exists($masterConfigFile)) {
- $container->addResource(new FileResource($masterConfigFile));
-
- $dom = XmlUtils::loadFile($masterConfigFile);
-
- $loopConfig = $this->processConfig($dom->getElementsByTagName("loop"));
-
- $filterConfig = $this->processConfig($dom->getElementsByTagName("filter"));
-
- $baseParamConfig = $this->processConfig($dom->getElementsByTagName("baseParam"));
-
- $loopTestConfig = $this->processConfig($dom->getElementsByTagName("testLoop"));
- }
+ $loader = new XmlFileLoader($container, new FileLocator(THELIA_ROOT . "/core/lib/Thelia"));
+ $loader->load("config.xml");
$modules = \Thelia\Model\ModuleQuery::getActivated();
foreach ($modules as $module) {
- $configFile = THELIA_PLUGIN_DIR . "/" . ucfirst($module->getCode()) . "/Config/config.xml";
- if (file_exists($configFile)) {
- $container->addResource(new FileResource($configFile));
- $dom = XmlUtils::loadFile($configFile);
- $loopConfig = array_merge($loopConfig, $this->processConfig($dom->getElementsByTagName("loop")));
-
- $filterConfig = array_merge($filterConfig, $this->processConfig($dom->getElementsByTagName("filter")));
-
- $baseParamConfig = array_merge(
- $baseParamConfig,
- $this->processConfig($dom->getElementsByTagName("baseParam"))
- );
-
- $loopTestConfig = array_merge(
- $loopTestConfig,
- $this->processConfig($dom->getElementsByTagName("testLoop"))
- );
+ try {
+ $loader = new XmlFileLoader($container, new FileLocator(THELIA_PLUGIN_DIR . "/" . ucfirst($module->getCode()) . "/Config"));
+ $loader->load("config.xml");
+ } catch(\InvalidArgumentException $e) {
}
}
-
- $container->setParameter("Tpex.loop", $loopConfig);
-
- $container->setParameter("Tpex.filter", $filterConfig);
-
- $container->setParameter("Tpex.baseParam", $baseParamConfig);
-
- $container->setParameter("Tpex.testLoop", $loopTestConfig);
-
- return $container;
- }
-
- protected function processConfig(\DOMNodeList $elements)
- {
- $result = array();
- for ($i = 0; $i < $elements->length; $i ++) {
- $element = XmlUtils::convertDomElementToArray($elements->item($i));
- $result[$element["name"]] = $element["class"];
- }
- return $result;
}
/**
@@ -233,8 +151,7 @@ class Thelia extends Kernel
{
$container = parent::buildContainer();
- $container = $this->loadConfiguration($container);
-
+ $this->loadConfiguration($container);
$container->customCompile();
return $container;
diff --git a/core/lib/Thelia/config.xml b/core/lib/Thelia/config.xml
index f51d6f494..e3ae73f70 100644
--- a/core/lib/Thelia/config.xml
+++ b/core/lib/Thelia/config.xml
@@ -1,8 +1,72 @@
-
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -255
+
+
+
+ -200
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/local/plugins/Test/Config/config.xml b/local/plugins/Test/Config/config.xml
index f9c2aeb0c..d68e49c37 100644
--- a/local/plugins/Test/Config/config.xml
+++ b/local/plugins/Test/Config/config.xml
@@ -1,6 +1,17 @@
-
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+