vendor/mondator/src/Mandango/Mondator/ClassExtension.php
changeset 18 c85b9d1ddf19
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/mondator/src/Mandango/Mondator/ClassExtension.php	Thu Oct 27 05:47:14 2011 +0200
@@ -0,0 +1,461 @@
+<?php
+
+/*
+ * This file is part of Mandango.
+ *
+ * (c) Pablo Díez <pablodip@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace Mandango\Mondator;
+
+use Mandango\Mondator\Definition\Method;
+use Mandango\Mondator\Definition\Property;
+
+/**
+ * ClassExtension is the base class for class extensions.
+ *
+ * @author Pablo Díez <pablodip@gmail.com>
+ *
+ * @api
+ */
+abstract class ClassExtension
+{
+    private $options;
+    private $requiredOptions;
+
+    protected $definitions;
+
+    protected $class;
+    protected $configClasses;
+    protected $configClass;
+
+    protected $newClassExtensions;
+    protected $newConfigClasses;
+
+    protected $twig;
+    protected $twigTempDir;
+
+    /**
+     * Constructor.
+     *
+     * @param array $options An array of options.
+     *
+     * @api
+     */
+    public function __construct(array $options = array())
+    {
+        $this->options = array();
+        $this->requiredOptions = array();
+
+        $this->setUp();
+
+        foreach ($options as $name => $value) {
+            $this->setOption($name, $value);
+        }
+
+        // required options
+        if ($diff = array_diff($this->requiredOptions, array_keys($options))) {
+            throw new \RuntimeException(sprintf('%s requires the options: "%s".', get_class($this), implode(', ', $diff)));
+        }
+    }
+
+    /**
+     * Set up the extension.
+     *
+     * @api
+     */
+    protected function setUp()
+    {
+    }
+
+    /**
+     * Add an option.
+     *
+     * @param string $name         The option name.
+     * @param mixed  $defaultValue The default value (optional, null by default).
+     *
+     * @api
+     */
+    protected function addOption($name, $defaultValue = null)
+    {
+        $this->options[$name] = $defaultValue;
+    }
+
+    /**
+     * Add options.
+     *
+     * @param array $options An array with options (name as key and default value as value).
+     *
+     * @api
+     */
+    protected function addOptions(array $options)
+    {
+        foreach ($options as $name => $defaultValue) {
+            $this->addOption($name, $defaultValue);
+        }
+    }
+
+    /**
+     * Add a required option.
+     *
+     * @param string $name The option name.
+     *
+     * @api
+     */
+    protected function addRequiredOption($name)
+    {
+        $this->addOption($name);
+
+        $this->requiredOptions[] = $name;
+    }
+
+    /**
+     * Add required options.
+     *
+     * @param array $options An array with the name of the required option as value.
+     *
+     * @api
+     */
+    protected function addRequiredOptions(array $options)
+    {
+        foreach ($options as $name) {
+            $this->addRequiredOption($name);
+        }
+    }
+
+    /**
+     * Returns if exists an option.
+     *
+     * @param string $name The name.
+     *
+     * @return bool Returns true if the option exists, false otherwise.
+     *
+     * @api
+     */
+    public function hasOption($name)
+    {
+        return array_key_exists($name, $this->options);
+    }
+
+    /**
+     * Set an option.
+     *
+     * @param string $name  The name.
+     * @param mixed  $value The value.
+     *
+     * @throws \InvalidArgumentException If the option does not exists.
+     *
+     * @api
+     */
+    public function setOption($name, $value)
+    {
+        if (!$this->hasOption($name)) {
+            throw new \InvalidArgumentException(sprintf('The option "%s" does not exists.', $name));
+        }
+
+        $this->options[$name] = $value;
+    }
+
+    /**
+     * Returns the options.
+     *
+     * @return array The options.
+     *
+     * @api
+     */
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    /**
+     * Return an option.
+     *
+     * @param string $name The name.
+     *
+     * @return mixed The value of the option.
+     *
+     * @throws \InvalidArgumentException If the options does not exists.
+     *
+     * @api
+     */
+    public function getOption($name)
+    {
+        if (!$this->hasOption($name)) {
+            throw new \InvalidArgumentException(sprintf('The option "%s" does not exists.', $name));
+        }
+
+        return $this->options[$name];
+    }
+
+    /**
+     * New class extensions process.
+     *
+     * @param string       $class              The class.
+     * @param \ArrayObject $configClasses      The config classes.
+     * @param \ArrayObject $newClassExtensions The new class extensions.
+     *
+     * @api
+     */
+    public function newClassExtensionsProcess($class, \ArrayObject $configClasses, \ArrayObject $newClassExtensions)
+    {
+        $this->class = $class;
+        $this->configClasses = $configClasses;
+        $this->configClass = $configClasses[$class];
+        $this->newClassExtensions = $newClassExtensions;
+
+        $this->doNewClassExtensionsProcess();
+
+        $this->class = null;
+        $this->configClasses = null;
+        $this->configClass = null;
+        $this->newClassExtensions = null;
+    }
+
+    /**
+     * Do the new class extensions process.
+     *
+     * Here you can add new class extensions.
+     *
+     * @api
+     */
+    protected function doNewClassExtensionsProcess()
+    {
+    }
+
+    /**
+     * New config classes process.
+     *
+     * @param string       $class            The class.
+     * @param \ArrayObject $configClasses    The config classes.
+     * @param \ArrayObject $newConfigClasses The new config classes.
+     *
+     * @api
+     */
+    public function newConfigClassesProcess($class, \ArrayObject $configClasses, \ArrayObject $newConfigClasses)
+    {
+        $this->class = $class;
+        $this->configClasses = $configClasses;
+        $this->configClass = $configClasses[$class];
+        $this->newConfigClasses = $newConfigClasses;
+
+        $this->doNewConfigClassesProcess();
+
+        $this->class = null;
+        $this->configClasses = null;
+        $this->configClass = null;
+        $this->newConfigClasses = null;
+    }
+
+    /**
+     * Do the new config classes process.
+     *
+     * Here you can add new config classes, and change the config classes
+     * if it is necessary to build the new config classes.
+     *
+     * @api
+     */
+    protected function doNewConfigClassesProcess()
+    {
+    }
+
+    /**
+     * Process the config class.
+     *
+     * @param string       $class         The class.
+     * @param \ArrayObject $configClasses The config classes.
+     *
+     * @api
+     */
+    public function configClassProcess($class, \ArrayObject $configClasses)
+    {
+        $this->class = $class;
+        $this->configClasses = $configClasses;
+        $this->configClass = $configClasses[$class];
+
+        $this->doConfigClassProcess();
+
+        $this->class = null;
+        $this->configClasses = null;
+        $this->configClass = null;
+    }
+
+    /**
+     * Do the config class process.
+     *
+     * Here you can modify the config class.
+     *
+     * @api
+     */
+    protected function doConfigClassProcess()
+    {
+    }
+
+
+    /**
+     * Process the class.
+     *
+     * @param string                      $class         The class.
+     * @param \ArrayObject                $configClasses The config classes.
+     * @param Mandango\Mondator\Container $container     The container.
+     *
+     * @api
+     */
+    public function classProcess($class, \ArrayObject $configClasses, Container $container)
+    {
+        $this->class = $class;
+        $this->configClasses = $configClasses;
+        $this->configClass = $configClasses[$class];
+        $this->definitions = $container;
+
+        $this->doClassProcess();
+
+        $this->class = null;
+        $this->configClasses = null;
+        $this->configClass = null;
+        $this->definitions = null;
+    }
+
+    /**
+     * Do the class process.
+     *
+     * @api
+     */
+    protected function doClassProcess()
+    {
+    }
+
+    /**
+     * Twig.
+     */
+    protected function processTemplate(Definition $definition, $name, array $variables = array())
+    {
+        $twig = $this->getTwig();
+
+        $variables['options'] = $this->options;
+        $variables['class'] = $this->class;
+        $variables['config_class'] = $this->configClass;
+        $variables['config_classes'] = $this->configClasses;
+
+        $result = $twig->loadTemplate($name)->render($variables);
+
+        // properties
+        $expression = '/
+            (?P<docComment>\ \ \ \ \/\*\*\n[\s\S]*\ \ \ \ \ \*\/)?\n?
+             \ \ \ \ (?P<static>static\ )?
+            (?P<visibility>public|protected|private)
+            \s
+            \$
+            (?P<name>[a-zA-Z0-9_]+)
+            ;
+        /xU';
+        preg_match_all($expression, $result, $matches);
+
+        for ($i = 0; $i <= count($matches[0]) - 1; $i++) {
+            $property = new Property($matches['visibility'][$i], $matches['name'][$i], null);
+            if ($matches['static'][$i]) {
+                $property->setStatic(true);
+            }
+            if ($matches['docComment'][$i]) {
+                $property->setDocComment($matches['docComment'][$i]);
+            }
+            $definition->addProperty($property);
+        }
+
+        // methods
+        $expression = '/
+            (?P<docComment>\ \ \ \ \/\*\*\n[\s\S]*\ \ \ \ \ \*\/)?\n
+            \ \ \ \ (?P<static>static\ )?
+            (?P<visibility>public|protected|private)
+            \s
+            function
+            \s
+            (?P<name>[a-zA-Z0-9_]+)
+            \((?P<arguments>[$a-zA-Z0-9_\\\=\(\), ]*)\)
+            \n
+            \ \ \ \ \{
+                (?P<code>[\s\S]*)
+            \n\ \ \ \ \}
+        /xU';
+        preg_match_all($expression, $result, $matches);
+
+        for ($i = 0; $i <= count($matches[0]) - 1; $i++) {
+            $code = trim($matches['code'][$i], "\n");
+            $method = new Method($matches['visibility'][$i], $matches['name'][$i], $matches['arguments'][$i], $code);
+            if ($matches['static'][$i]) {
+                $method->setStatic(true);
+            }
+            if ($matches['docComment'][$i]) {
+                $method->setDocComment($matches['docComment'][$i]);
+            }
+            $definition->addMethod($method);
+        }
+    }
+
+    public function getTwig()
+    {
+        if (null === $this->twig) {
+            if (!class_exists('Twig_Environment')) {
+                throw new \RuntimeException('Twig is required to use templates.');
+            }
+
+            $loader = new \Twig_Loader_String();
+            $twig = new \Twig_Environment($loader, array(
+                'autoescape'       => false,
+                'strict_variables' => true,
+                'debug'            => true,
+                'cache'            => $this->twigTempDir = sys_get_temp_dir().'Mondator/'.mt_rand(111111, 999999),
+            ));
+
+            $this->configureTwig($twig);
+
+            $this->twig = $twig;
+        }
+
+        return $this->twig;
+    }
+
+    protected function configureTwig(\Twig_Environment $twig)
+    {
+    }
+
+    /*
+     * Tools.
+     */
+    protected function createClassExtensionFromArray(array $data)
+    {
+        if (!isset($data['class'])) {
+            throw new \InvalidArgumentException(sprintf('The extension does not have class.'));
+        }
+
+        return new $data['class'](isset($data['options']) ? $data['options'] : array());
+    }
+
+    private function removeDir($target)
+    {
+        $fp = opendir($target);
+        while (false !== $file = readdir($fp)) {
+            if (in_array($file, array('.', '..'))) {
+                continue;
+            }
+
+            if (is_dir($target.'/'.$file)) {
+                self::removeDir($target.'/'.$file);
+            } else {
+                unlink($target.'/'.$file);
+            }
+        }
+        closedir($fp);
+        rmdir($target);
+    }
+
+    public function __destruct()
+    {
+        if ($this->twigTempDir && is_dir($this->twigTempDir)) {
+            $this->removeDir($this->twigTempDir);
+        }
+    }
+}