<?php
/**
 * Generic dispatcher.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Mvc
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Mvc;

use Ding\Reflection\IReflectionFactoryAware;
use Ding\Reflection\IReflectionFactory;
use Ding\Logger\ILoggerAware;
use Ding\Mvc\Exception\MvcException;
use Ding\Mvc\DispatchInfo;

/**
 * Generic dispatcher.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Mvc
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 */
abstract class Dispatcher implements ILoggerAware, IReflectionFactoryAware
{
    /**
     * log4php logger or our own.
     * @var Logger
     */
    private $_logger;
    /**
     * A ReflectionFactory implementation.
     * @var IReflectionFactory
     */
    protected $reflectionFactory;

    /**
     * @var IHandlerInterceptor[]
     */
    private $_interceptors = array();

    /**
     * Main action. Will use the action mapper to get a controller that can
     * handle the given Action, and then the viewresolver to get a View that
     * can render the returned ModelAndView from the controller.
     *
     * @param Action  $action Action to dispatch.
     *
     * @throws MvcException
     * @return void
     */
    public function dispatch(DispatchInfo $dispatchInfo)
    {
        $controller = $dispatchInfo->handler;
        $actionHandler = $dispatchInfo->method;
        $action = $dispatchInfo->action;
        if (!method_exists($controller, $actionHandler)) {
            throw new MvcException('No valid action handler found: ' . $actionHandler);
        }
        $interceptors = $dispatchInfo->interceptors;
        $filtersPassed = true;
        $result = false;
        foreach ($interceptors as $interceptor) {
            $this->_logger->debug("Running pre filter: " . get_class($interceptor));
            $result = $interceptor->preHandle($action, $controller);
            if ($result === false) {
                $filtersPassed = false;
                $this->_logger->debug("Filter returned false, stopping dispatch");
                break;
            } else if ($result instanceof ModelAndView) {
                return $result;
            }
        }
        if ($filtersPassed) {
            $result = $this->invokeAction($controller, $actionHandler, $action->getArguments());
            foreach ($interceptors as $interceptor) {
                $this->_logger->debug("Running post filter: " . get_class($interceptor));
                $interceptor->postHandle($action, $controller);
            }
        }
        return $result;
    }

	/**
     * Calls the specified method from the specifed object using the specified
     * arguments map.
     *
     * @param object $object
     * @param string $method Method name
     * @param array $arguments Map of arguments, where key is argument name,
     * and value is argument value.
     *
     * @return mxied
     */
    private function invokeAction($object, $method, array $arguments)
    {
        $methodInfo = $this->reflectionFactory->getMethod(
            get_class($object), $method
        );
        $parameters = $methodInfo->getParameters();
        $values = array();
        $total = count($parameters);
        for ($i = 0; $i < $total; $i++) {
            $parameter = array_shift($parameters);
            $name = $parameter->getName();
            if (isset($arguments[$name])) {
                $values[] = $arguments[$name];
            } else if ($parameter->isOptional()) {
                $values[] = $parameter->getDefaultValue();
            } else {
                $ctl = get_class($object);
                throw new MvcException(
                	"Missing required argument: $name for action $ctl:$method"
                );
            }
        }
        return $methodInfo->invokeArgs($object, $values);
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Reflection.IReflectionFactoryAware::setReflectionFactory()
     */
    public function setReflectionFactory(IReflectionFactory $reflectionFactory)
    {
        $this->reflectionFactory = $reflectionFactory;
    }
    /**
     * (non-PHPdoc)
     * @see Ding\Logger.ILoggerAware::setLogger()
     */
    public function setLogger(\Logger $logger)
    {
        $this->_logger = $logger;
    }
}


<?php
/**
 * Twig view render.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Mvc
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Mvc\Http;

use Ding\Mvc\IViewRender;
use Ding\Mvc\View;

/**
 * Twig view render.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Mvc
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 */
class TwigViewRender implements IViewRender
{
    /**
     * TWIG options.
     * @var string[]
     */
    private $_twigOptions = array();

    /**
     * Sets TWIG options.
     *
     * @param string[] $options TWIG options.
     *
     * @return void
     */
    public function setTwigOptions(array $options)
    {
        $this->_twigOptions = $options;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Mvc.IViewRender::render()
     */
    public function render(View $view)
    {
        /**
         * @todo is there a better way to do this?
         */
        global $modelAndView;
        $modelAndView = $view->getModelAndView();
        require_once 'Twig' . DIRECTORY_SEPARATOR . 'Autoloader.php';
        \Twig_Autoloader::register();
        $loader = new \Twig_Loader_Filesystem(dirname($view->getPath()));
        $twig = new \Twig_Environment($loader, array($this->_twigOptions));
        $template = $twig->loadTemplate(basename($view->getPath()));
        echo $template->render(array('vars' => $modelAndView->getModel()));
    }
}


<?php
/**
 * Tcp Peer: encapsulated data and operations for each peer conected to the
 * Tcp Server helper.
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Helpers
 * @subpackage Tcp
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Helpers\Tcp;

use Ding\Helpers\Tcp\Exception\TcpException;

/**
 * Tcp Peer: encapsulated data and operations for each peer conected to the
 * Tcp Server helper.
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Helpers
 * @subpackage Tcp
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 */
class TcpPeer
{
    /**
     * @var string
     */
    protected $address;
    /**
     * @var integer
     */
    protected $port;

    /**
     * @var resource
     */
    protected $socket;
    /**
     * Writes to this peer.
     *
     * @param string $what What to write.
     *
     * @return integer
     */
    public function write($what)
    {
        $ret = null;
        if ($this->isConnected()) {
            $ret = @socket_send($this->socket, $what, strlen($what), 0);
        }
        return $ret;
    }
    /**
     * Writes to this peer.
     *
     * @param string  &$buffer Where to put read data.
     * @param integer $length  Maximum data to read.
     * @param boolean $peek    True to just take a peek to the data.
     *
     * @return integer
     */
    public function read(&$buffer, $length, $peek = false)
    {
        $ret = null;
        if ($this->isConnected()) {
            $length = @socket_recv($this->socket, $buffer, $length, $peek ? MSG_PEEK : 0);
            $ret = $length;
        }
        return $ret;
    }
    /**
     * Call this to disconnect the peer.
     *
     * @return void
     */
    public function disconnect()
    {
        if ($this->isConnected()) {
            @socket_close($this->socket);
            $this->socket = null;
        }
    }

    /**
     * Returns true if this peer is still connected.
     *
     * @return boolean
     */
    public function isConnected()
    {
        return $this->socket !== null;
    }
    /**
     * Call this one to see if this peer has any activity in the socket.
     *
     * @return boolean
     */
    public function hasActivity()
    {
        if (!$this->isConnected()) {
            return false;
        }
        $read = array($this->socket);
        $write = null;
        $ex = null;
        $result = socket_select($read, $write, $ex, 0, 0);
        if ($result === false) {
            throw new TcpException(
            	'Error selecting from socket: '
                . socket_strerror(socket_last_error($this->socket))
            );
        }
        return !empty($read);
    }

    /**
     * Returns the ip address for this peer.
     *
     * @return string
     */
    public function getAddress()
    {
        return $this->address;
    }

    /**
     * Returns the port number for this peer.
     *
     * @return integer
     */
    public function getPort()
    {
        return $this->port;
    }

    /**
     * Returns ip:port
     *
     * @return string
     */
    public function getName()
    {
        return $this->address . ':' . $this->port;
    }

    /**
     * Returns open socket for this peer.
     *
     * @return resoucce
     */
    public function getSocket()
    {
        return $this->socket;
    }
    /**
     * Constructor.
     *
     * @param string   $address IP for this peer.
     * @param integer  $port    Port number for this peer.
     * @param resource $socket Socket for this peer.
     */
    public function __construct($address, $port, $socket)
    {
        $this->address = $address;
        $this->port = $port;
        $this->socket = $socket;
    }
}


<?php
/**
 * Container implementation.
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Container
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Container\Impl;

use Ding\Helpers\ErrorHandler\ErrorInfo;

use Ding\Bean\IBeanDefinitionProvider;
use Ding\Cache\Impl\DummyCacheImpl;
use Ding\Bean\Provider\Core;
use Ding\Resource\Impl\IncludePathResource;
use Ding\Resource\Impl\FilesystemResource;
use Ding\Resource\Impl\URLResource;
use Ding\Cache\Locator\CacheLocator;
use Ding\Container\IContainer;
use Ding\Aspect\AspectManager;
use Ding\Aspect\InterceptorDefinition;
use Ding\Aspect\AspectDefinition;
use Ding\Aspect\Interceptor\IDispatcher;
use Ding\Aspect\Interceptor\DispatcherImpl;
use Ding\Reflection\ReflectionFactory;
use Ding\Bean\Lifecycle\BeanLifecycle;
use Ding\Bean\Lifecycle\BeanLifecycleManager;
use Ding\Bean\Factory\Exception\BeanFactoryException;
use Ding\Bean\BeanConstructorArgumentDefinition;
use Ding\Bean\BeanDefinition;
use Ding\Bean\BeanPropertyDefinition;
use Ding\MessageSource\IMessageSource;

/**
 * Container implementation.
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Container
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 */
class ContainerImpl implements IContainer
{
    /**
     * Logger.
     * @var Logger
     */
    private $_logger;

    /**
     * Cache for isDebugEnabled()
     * @var boolean
     */
    private $_logDebugEnabled;

    /**
     * Dispatcher to be cloned for proxy.
     * @var DispatcherImpl
     */
    private $_dispatcherTemplate = null;

    /**
     * MessageSource implementation.
     * @var IMessageSource
     */
    private $_messageSource = false;
    /**
     * Default options.
     * @var array
     */
    private static $_options = array(
        'bdef' => array(),
        'properties' => array(),
        'drivers' => array()
    );

    /**
     * Registered shutdown methods for beans (destroy-methods).
     * @var array
     */
    private $_shutdowners = array();

    /**
     * Beans already instantiated.
     * @var object[]
     */
    private $_beans;

    /**
     * Holds our beans cache.
     * @var ICache
     */
    private $_beanCache;

    /**
     * Beans already instantiated.
     * @var BeanDefinition[]
     */
    private $_beanDefs;

    /**
     * Beans aliases.
     * @var string[]
     */
    private $_beanAliases;

    /**
     * Holds our bean definitions cache.
     * @var ICache
     */
    private $_beanDefCache;

    /**
     * Container instance.
     * @var ContainerImpl
     */
    private static $_containerInstance = false;

    /**
     * The aspect manager.
     * @var AspectManager
     */
    private $_aspectManager = null;

    /**
     * The lifecycle manager.
     * @var BeanLifecycleManager
     */
    private $_lifecycleManager = null;

    /**
     * Resources multiton.
     * @var IResource[]
     */
    private $_resources = false;

    /**
     * The event listeners
     * @var string[]
     */
    private $_eventListeners = false;

    /**
     * Bean Definition providers.
     * @var IBeanDefinitionProvider[]
     */
    private $_beanDefinitionProviders = array();

    /**
     * The last error message is saved, just to avoid logging repeated messages.
     * @var string
     */
    private $_lastErrorMessage;

    /**
     * A ReflectionFactory implementation
     * @var IReflectionFactory
     */
    private $_reflectionFactory;

    /**
     * A Proxy factory implementation.
     * @var Proxy
     */
    private $_proxyFactory;

    /**
     * Properties configured when instantiating the container and by others,
     * like when using a PropertiesHolder.
     *
     * @var string[]
     */
    private $_properties;

    /**
     * Horrible state keeper for getBeanDefinition() to avoid following cyclic
     * dependencies.
     * @var string[]
     */
    private $_definitionsInProcess = array();

    /**
     * Prevent serialization.
     *
     * @return array
     */
    public function __sleep()
    {
        return array('_aspectManager', '_lifecycleManager');
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
     */
    public function getBeansByClass($class)
    {
        $cacheKey = "$class.knownByClass";
        $ret = $this->_beanDefCache->fetch($cacheKey, $result);
        if ($result === true) {
            return $ret;
        }
        $ret = array();
        foreach ($this->_beanDefinitionProviders as $provider) {
            $ret = array_merge($ret, $provider->getBeansByClass($class));
        }
        $this->_beanDefCache->store($cacheKey, $ret);
        return $ret;
    }
    /**
     * Returns a bean definition.
     *
     * @param string $name Bean name.
     *
     * @return BeanDefinition
     * @throws BeanFactoryException
     */
    public function getBeanDefinition($name)
    {
        if (isset($this->_beanAliases[$name])) {
            $name = $this->_beanAliases[$name];
        }
        if (isset($this->_beanDefs[$name])) {
            return $this->_beanDefs[$name];
        }
        $beanDefinition = null;
        if ($this->_beanDefCache !== null) {
            $beanDefinition = $this->_beanDefCache->fetch($name, $result);
        }
        if ($beanDefinition) {
            $this->_beanDefs[$name] = $beanDefinition;
            return $beanDefinition;
        }
        foreach ($this->_beanDefinitionProviders as $provider) {
            $beanDefinition = $provider->getBeanDefinition($name);
            if ($beanDefinition) {
                $beanDefinition->setClass($this->_searchAndReplaceProperties(
                    $beanDefinition->getClass()
                ));
                break;
            }
        }
        if (!$beanDefinition) {
            throw new BeanFactoryException('Unknown bean: ' . $name);
        }
        $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
        $this->_beanDefs[$name] = $beanDefinition;
        $this->_beanDefCache->store($name, $beanDefinition);
        foreach ($beanDefinition->getAliases() as $alias) {
            $this->_beanAliases[$alias] = $name;
        }
        return $beanDefinition;
    }

    /**
     * Will try to search and replace the properties found in the given
     * value.
     *
     * @param string $value
     *
     * @return string
     */
    private function _searchAndReplaceProperties($value)
    {
        if (is_string($value)) {
            foreach ($this->_properties as $k => $v) {
                if (strpos($value, $k) !== false) {
                    if (is_string($v)) {
                        $value = str_replace($k, $v, $value);
                    } else {
                        $value = $v;
                        // Assigned value is not a string, so we cant use
                        // strpos anymore on it (i.e: cant continue replacing)
                        break;
                    }
                }
            }
        }
        return $value;
    }

    /**
     * Takes care of transforming a scalar value for a property or constructor
     * argument, into a an actual value (i.e: if its a resource://, loading it
     * first).
     *
     * @param mixed $value The value
     *
     * @return mixed
     */
    private function _loadValue($value)
    {
        $value = $this->_searchAndReplaceProperties($value);
        if (is_string($value) && strpos($value, 'resource://') === 0) {
            $value = substr($value, 11);
            return $this->getResource($value);
        }
        return $value;
    }

    /**
     * This will resolve a property (or constructor arg) definition to a final
     * value, being a bean reference, array of other properties (or
     * constructor args), etc.
	 *
     * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
     *
     * @return void
     */
    private function _getValueFromDefinition($what)
    {
        $value = null;
        if ($what->isBean()) {
            $value = $this->getBean($what->getValue());
        } else if ($what->isArray()) {
            $value = array();
            foreach ($what->getValue() as $k => $v) {
                $value[$k] = $this->_getValueFromDefinition($v);
            }
        } else if ($what->isCode()) {
            $value = eval($what->getValue());
        } else {
            $value = $this->_loadValue($what->getValue());
        }
        return $value;
    }

    /**
     * Resolves all values for constructor arguments definitions in a
     * bean definition.
     *
     * @param BeanDefinition $definition
     *
     * @return object
     */
    private function _getConstructorValuesForDefinition($definition)
    {
        $args = array();
        foreach ($definition->getArguments() as $argument) {
            $value = $this->_getValueFromDefinition($argument);
            if ($argument->hasName()) {
                $name = $argument->getName();
                $args[$name] = $value;
            } else {
                $args[] = $value;
            }
        }
        return $args;
    }

    /**
     * Instantiates a bean using the constructor.
     *
     * @param BeanDefinition $definition
     *
     * @return object
     */
    private function _instantiateByConstructor(BeanDefinition $definition)
    {
        $class = $definition->getClass();
        if ($definition->hasProxyClass()) {
            $class = $definition->getProxyClassName();
        }
        $rClass = $this->_reflectionFactory->getClass($class);
        $factoryMethod = $rClass->getConstructor();
        if ($factoryMethod !== null) {
            $args = $this->_sortArgsWithNames($definition, $factoryMethod);
            if (empty($args)) {
                return $rClass->newInstanceArgs();
            } else {
                return $rClass->newInstanceArgs($args);
            }
        } else {
            return $rClass->newInstanceArgs();
        }
    }

    /**
     * Instantiates a bean using a factory class.
     *
     * @param BeanDefinition $definition
     *
     * @return object
     */
    private function _instantiateByFactoryClass(BeanDefinition $definition)
    {
        $class = $definition->getClass();
        $rClass = $this->_reflectionFactory->getClass($class);
        $factoryMethodName = $definition->getFactoryMethod();
        $factoryMethod = $rClass->getMethod($factoryMethodName);
        $args = $this->_sortArgsWithNames($definition, $factoryMethod);
        return forward_static_call_array(array($class, $factoryMethodName), $args);
    }

    /**
     * Instantiates a bean using a factory bean.
     *
     * @param BeanDefinition $definition
     *
     * @return object
     */
    private function _instantiateByFactoryBean(BeanDefinition $definition)
    {
        $factoryBean = $this->getBean($definition->getFactoryBean());
        $refObject = new \ReflectionObject($factoryBean);
        $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
        $args = $this->_sortArgsWithNames($definition, $factoryMethod);
        return $factoryMethod->invokeArgs($factoryBean, $args);
    }

    private function _sortArgsWithNames(BeanDefinition $definition, \ReflectionMethod $rMethod)
    {
        $args = $this->_getConstructorValuesForDefinition($definition);
        $callArgs = array();
        foreach ($rMethod->getParameters() as $parameter) {
            $parameterName = $parameter->getName();
            if (isset($args[$parameterName])) {
                $callArgs[] = $args[$parameterName];
                unset($args[$parameterName]);
            }
        }
        foreach ($args as $value) {
            $callArgs[] = $value;
        }
        return $callArgs;
    }

    /**
     * Instantiates a bean.
     *
     * @param BeanDefinition $definition
     *
     * @return object
     */
    private function _instantiate(BeanDefinition $definition)
    {
        if ($definition->isCreatedByConstructor()) {
            return $this->_instantiateByConstructor($definition);
        } else if ($definition->isCreatedWithFactoryBean()) {
            return $this->_instantiateByFactoryBean($definition);
        } else {
            return $this->_instantiateByFactoryClass($definition);
        }
    }

    /**
     * Creates whatever beans this definition depends on.
     *
     * @return void
     */
    private function _createBeanDependencies(BeanDefinition $definition)
    {
        foreach ($definition->getDependsOn() as $depBean) {
            $this->getBean(trim($depBean));
        }
    }

    /**
     * Will inject into the given dispatcher the necessary information to
     * aspects will be run correctly.
     *
     * @throws BeanFactoryException
     * @return void
     */
    private function _applyAspect(
        $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
    ) {
        $rClass = $this->_reflectionFactory->getClass($targetClass);
        $aspect = $this->getBean($aspectDefinition->getBeanName());
        foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
            $pointcut = $this->_aspectManager->getPointcut($pointcutName);
            if ($pointcut === false) {
                throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
            }
            $expression = $pointcut->getExpression();
            foreach  ($rClass->getMethods() as $method) {
                $methodName = $method->getName();
                if (preg_match('/' . $expression . '/', $methodName) === 0) {
                    continue;
                }
                if (
                    $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
                ) {
                    $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
                } else {
                    $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
                }
            }
        }
    }

    /**
     * Applies all aspects specifically defined for this bean definition.
     *
     * @param BeanDefinition $definition
     * @param IDispatcher $dispatcher
     *
     * @return void
     */
    private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
    {
        if ($definition->hasAspects()) {
            foreach ($definition->getAspects() as $aspect) {
                $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
            }
        }
    }

    /**
     * Looks for any global aspects that may apply to this bean and applies them.
     *
     * @param BeanDefinition $definition
     * @param IDispatcher $dispatcher
     *
     * @return void
     */
    private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
    {
        $class = $definition->getClass();
        $rClass = $this->_reflectionFactory->getClass($class);
        foreach ($this->_aspectManager->getAspects() as $aspect) {
            $expression = $aspect->getExpression();
            if (preg_match('/' . $expression . '/', $class) === 0) {
                $parentClass = $rClass->getParentClass();
                while($parentClass !== false) {
                    if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
                        $this->_applyAspect($class, $aspect, $dispatcher);
                    }
                    $parentClass = $parentClass->getParentClass();
                }
            } else {
                $this->_applyAspect($class, $aspect, $dispatcher);
            }
        }
    }

    /**
     * Applies specific bean aspects and global defined aspects.
     *
     * @param BeanDefinition $definition
     *
     * @return void
     */
    private function _applyAspects(BeanDefinition $definition)
    {
        $class = $definition->getClass();
        $dispatcher = clone $this->_dispatcherTemplate;
        $this->_applySpecificAspects($definition, $dispatcher);
        $this->_applyGlobalAspects($definition, $dispatcher);
        if ($dispatcher->hasMethodsIntercepted()) {
            $definition->setProxyClassName(
                $this->_proxyFactory->create($class, $dispatcher)
            );
        }
    }
    /**
     * This will create a new bean, injecting all properties and applying all
     * aspects.
     *
     * @throws BeanFactoryException
     * @return object
     */
    private function _createBean(BeanDefinition $definition)
    {
        $name = $definition->getName();
        if (isset($this->_definitionsInProcess[$name])) {
            throw new BeanFactoryException(
            	"Cyclic dependency found for: $name"
            );
        }
        $this->_definitionsInProcess[$name] = '';
        $this->_lifecycleManager->beforeCreate($definition);
        $this->_createBeanDependencies($definition);
        $this->_applyAspects($definition);
        $bean = $this->_instantiate($definition);
        if (!is_object($bean)) {
            unset($this->_definitionsInProcess[$name]);
            throw new BeanFactoryException(
            	'Could not instantiate ' . $definition->getName()
            );
        }
        $this->_assemble($bean, $definition);
        $this->_setupInitAndShutdown($bean, $definition);
        $this->_lifecycleManager->afterCreate($bean, $definition);
        unset($this->_definitionsInProcess[$name]);
        return $bean;
    }

    /**
     * Calls init method and register shutdown method.
     *
     * @param object $bean
     * @param BeanDefinition $definition
     *
     * @return void
     */
    private function _setupInitAndShutdown($bean, BeanDefinition $definition)
    {
        if ($definition->hasInitMethod()) {
            $initMethod = $definition->getInitMethod();
            $bean->$initMethod();
        }
        if ($definition->hasDestroyMethod()) {
            $destroyMethod = $definition->getDestroyMethod();
            $this->registerShutdownMethod($bean, $destroyMethod);
        }
    }

    /**
     * Tries to inject by looking up set* methods.
     *
     * @param object $bean
     * @param string $name
     * @param string $value
     *
     * @return boolean
     */
    private function _setterInject($bean, $name, $value)
    {
        $methodName = 'set' . ucfirst($name);
        $rClass = $this->_reflectionFactory->getClass(get_class($bean));
        if ($rClass->hasMethod($methodName)) {
            $bean->$methodName($value);
            return true;
        }
        return false;
    }

    /**
     * Tries to inject by looking up a method of the given name.
     *
     * @param object $bean
     * @param string $name
     * @param string $value
     *
     * @return boolean
     */
    private function _nonSetterMethodInject($bean, $name, $value)
    {
        $rClass = $this->_reflectionFactory->getClass(get_class($bean));
        if ($rClass->hasMethod($name)) {
            $bean->$name($value);
            return true;
        }
        return false;
    }

    /**
     * Tries to inject by looking up a property by name.
     *
     * @param object $bean
     * @param string $name
     * @param string $value
     *
     * @return boolean
     */
    private function _propertyInject($bean, $name, $value)
    {
        $rClass = $this->_reflectionFactory->getClass(get_class($bean));
        if ($rClass->hasProperty($name)) {
             $rProperty = $rClass->getProperty($name);
             if (!$rProperty->isPublic()) {
                $rProperty->setAccessible(true);
             }
            $rProperty->setValue($bean, $value);
            return true;
        }
        return false;
    }
    /**
     * Assembles a bean (setter injection)
     *
     * @param mixed $bean
     * @param BeanDefinition $beanDefinition
     *
     * @return void
     */
    private function _assemble($bean, BeanDefinition $beanDefinition)
    {
        $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
        foreach ($beanDefinition->getProperties() as $property) {
            $propertyName = $property->getName();
            $propertyValue = $this->_getValueFromDefinition($property);
            if (
                $this->_setterInject($bean, $propertyName, $propertyValue)
                || $this->_propertyInject($bean, $propertyName, $propertyValue)
                || $this->_nonSetterMethodInject($bean, $propertyName, $propertyValue)
            ) {
                continue;
            }
            throw new BeanFactoryException("Dont know how to inject: $propertyName");
        }
        $this->fillAware($beanDefinition, $bean);
        $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
    }
    /**
     * Returns a bean.
     *
     * @param string $name Bean name.
     *
     * @throws BeanFactoryException
     * @return object
     */
    public function getBean($name)
    {
        $ret = false;
        $beanDefinition = $this->getBeanDefinition($name);
        $beanName = $name . '.bean';
        if ($beanDefinition->isAbstract()) {
            throw new BeanFactoryException(
            	"Cant instantiate abstract bean: $name"
            );
        }
        if ($beanDefinition->isPrototype()) {
            $ret = $this->_createBean($beanDefinition);
        } else if ($beanDefinition->isSingleton()) {
            if (isset($this->_beans[$beanName])) {
                $ret = $this->_beans[$beanName];
            } else {
                $ret = $this->_beanCache->fetch($beanName, $result);
                if (!$ret) {
                    $ret = $this->_createBean($beanDefinition);
                }
                $this->_beans[$beanName] = $ret;
            }
        }
        return $ret;
    }

    /**
     * This will return a container
     *
     * @param array $properties Container properties.
     *
     * @return ContainerImpl
     */
    public static function getInstance(array $properties = array())
    {
        if (self::$_containerInstance === false) {
            // Init cache subsystems.
            if (isset($properties['ding']['cache'])) {
                CacheLocator::configure($properties['ding']['cache']);
            }
            if (isset($properties['ding']['log4php.properties'])) {
                \Logger::configure($properties['ding']['log4php.properties']);
            }
            self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
        }
        return self::$_containerInstance;
    }

    /**
     * Register a shutdown (destroy-method) method for a bean.
     *
     * @param object $bean   Bean to call.
     * @param string $method Method to call.
     *
     * @see Ding\Container.IContainer::registerShutdownMethod()
     *
     * @return void
     */
    public function registerShutdownMethod($bean, $method)
    {
        $this->_shutdowners[] = array($bean, $method);
    }

    /**
     * Destructor, will call all beans destroy-methods.
     *
     * @return void
     */
    public function __destruct()
    {
        foreach ($this->_shutdowners as $shutdownCall) {
            $bean = $shutdownCall[0];
            $method = $shutdownCall[1];
            $bean->$method();
        }
    }

    /**
     *
     * Enter description here ...
     * @param unknown_type $messageSource
     */
    public function setMessageSource(IMessageSource $messageSource)
    {
        $this->_messageSource = $messageSource;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\MessageSource.IMessageSource::getMessage()
     */
    public function getMessage($bundle, $message, array $arguments, $locale = 'default')
    {
        return
            $this->_messageSource !== false
            ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
            : NULL;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResourceLoader::getResource()
     */
    public function getResource($location, $context = false)
    {
        // Missing scheme?
        $scheme = strpos($location, '://');
        if ($scheme === false) {
            $location = FilesystemResource::SCHEME . $location;
        }
        // Already served?
        if (isset($this->_resources[$location])) {
            return $this->_resources[$location];
        }
        // See what kind of resource to return.
        if (strpos($location, FilesystemResource::SCHEME) === 0) {
            $resource = new FilesystemResource($location, $context);
        } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
            $resource = new IncludePathResource($location, $context);
        } else {
            $resource = new URLResource($location, $context);
        }
        $this->_resources[$location] = $resource;
        return $resource;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Bean.IBeanDefinitionProvider::getBeansListeningOn()
     */
    public function getBeansListeningOn($eventName)
    {
        if (isset($this->_eventListeners[$eventName])) {
            return $this->_eventListeners[$eventName];
        }
        return array();
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Container.IContainer::eventDispatch()
     */
    public function eventDispatch($eventName, $data = null)
    {
        if ($this->_logDebugEnabled) {
            $this->_logger->debug("Dispatching event: $eventName");
        }
        $listeners = $this->getBeansListeningOn($eventName);
        foreach ($this->_beanDefinitionProviders as $provider) {
            $listeners = array_merge($listeners, $provider->getBeansListeningOn($eventName));
        }
        $eventName = 'on' . ucfirst($eventName);
        foreach ($listeners as $beanName) {
            $bean = $this->getBean($beanName);
            $bean->$eventName($data);
        }
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Container.IContainer::eventListen()
     */
    public function eventListen($eventName, $beanName)
    {
        if (!isset($this->_eventListeners[$eventName])) {
            $this->_eventListeners[$eventName] = array();
        }
        $this->_eventListeners[$eventName][] = $beanName;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
     */
    public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
    {
        $this->_beanDefinitionProviders[] = $provider;
    }

    /**
     * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
     * getBean() yet), replace it with this one.
     *
     * @param string $class The name of a class.
     *
     * @return ReflectionClass
     */
    protected function getClass($class)
    {
        return new \ReflectionClass($class);
    }

    /**
     * Will look for "aware" kind of interfaces and inject whatever necessary.
     *
     * @param BeanDefinition $def The Bean Definition
     * @param object $bean The bean
     *
     * @return void
     */
    public function fillAware(BeanDefinition $def, $bean)
    {
        $class = get_class($bean);
        $rClass = $this->_reflectionFactory->getClass($class);
        if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
            $bean->setReflectionFactory($this->_reflectionFactory);
        }
        if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
            $bean->setBeanName($def->getName());
        }
        if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
            $bean->setLogger(\Logger::getLogger($class));
        }
        if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
            $bean->setContainer($this);
        }
        if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
            $bean->setResourceLoader($this);
        }
        if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
            $bean->setAspectManager($this->_aspectManager);
        }

        if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
            $this->registerBeanDefinitionProvider($bean);
        }
        if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
            $this->_lifecycleManager->addAfterConfigListener($bean);
        }
        if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
            $this->_lifecycleManager->addAfterDefinitionListener($bean);
        }
        if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
            $this->_lifecycleManager->addBeforeCreateListener($bean);
        }
        if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
            $this->_lifecycleManager->addAfterCreateListener($bean);
        }
        if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
            $this->_lifecycleManager->addBeforeAssembleListener($bean);
        }
        if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
            $this->_lifecycleManager->addAfterAssembleListener($bean);
        }
        if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
            $this->_aspectManager->registerAspectProvider($bean);
        }
        if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
            $this->_aspectManager->registerPointcutProvider($bean);
        }
    }

    /**
     * Called when a signal is caught.
     *
     * @param integer $signo
     *
     * @return void
     */
    public function signalHandler($signo)
    {
        $msg = "Caught Signal: $signo";
        $this->_logger->warn($msg);
        $this->eventDispatch('dingSignal', $signo);
    }

    /**
     * Called by php after set_error_handler()
     *
     * @param integer $type
     * @param string $message
     * @param string $file
     * @param integer $line
     *
     * @return true
     */
    public function errorHandler($type, $message, $file, $line)
    {
        $msg = "$message in $file:$line";
        if ($msg == $this->_lastErrorMessage) {
            return;
        }
        $this->_lastErrorMessage = $msg;
        $this->_logger->error($msg);
        $this->eventDispatch(
            'dingError', new ErrorInfo($type, $message, $file, $line)
        );
        return true;
    }

    // @codeCoverageIgnoreStart
    /**
     * Called by the vm after register_shutdown_function()
     *
     * @return void
     */
    public function shutdownHandler()
    {
        $msg = "Shutting down";
        $this->eventDispatch('dingShutdown');
    }
    // @codeCoverageIgnoreEnd

    /**
     * (non-PHPdoc)
     * @see Ding\Container.IContainer::registerProperties()
     */
    public function registerProperties(array $properties)
    {
        foreach ($properties as $key => $value) {
            if (strncmp($key, 'php.', 4) === 0) {
                ini_set(substr($key, 4), $value);
            }
            $this->_properties['${' . $key . '}'] = $value;
        }
    }

    /**
     * Constructor.
     *
     * @param array $options options.
     *
     * @return void
     */
    protected function __construct(array $options)
    {
        // Setup logger.
        $this->_logger = \Logger::getLogger(get_class($this));
        $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
        $soullessArray = array();
        $this->_beanAliases = $soullessArray;
        $this->_beanDefs = $soullessArray;
        $this->_beans = $soullessArray;
        $this->_shutdowners = $soullessArray;
        $this->_resources = $soullessArray;
        $this->_eventListeners = $soullessArray;
        $this->_properties = $soullessArray;

        // Merge options with our defaults.
        self::$_options = array_replace_recursive(self::$_options, $options);
        $this->registerProperties(self::$_options['properties']);
        $sapi = php_sapi_name();
        if (function_exists('pcntl_signal')) {
            if ($sapi == 'cgi' || $sapi == 'cli') {
                $signals = array(
                    SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
                );
                $handler = array($this, 'signalHandler');
                foreach ($signals as $signal) {
                    pcntl_signal($signal, $handler);
                }
                pcntl_sigprocmask(SIG_UNBLOCK, $signals);
            }
        }
        set_error_handler(array($this, 'errorHandler'));
        register_shutdown_function(array($this, 'shutdownHandler'));

        $this->_lifecycleManager = new BeanLifecycleManager;
        $this->_dispatcherTemplate = new DispatcherImpl();
        $this->_aspectManager = new AspectManager();
        $this->_aspectManager->setCache(DummyCacheImpl::getInstance());
        $this->_beanDefCache = DummyCacheImpl::getInstance();
        $this->_beanCache = DummyCacheImpl::getInstance();
        $this->registerBeanDefinitionProvider(new Core(self::$_options));
        $this->_reflectionFactory = $this;
        $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
        $this->_proxyFactory = $this->getBean('dingProxyFactory');
        $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
        $this->_beanCache = $this->getBean('dingBeanCache');
        $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
        $this->_aspectManager = $this->getBean('dingAspectManager');
        $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');

        // Set drivers
        if (isset(self::$_options['bdef']['xml'])) {
            $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
        }
        if (isset(self::$_options['bdef']['yaml'])) {
            $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
        }
        $this->getBean('dingPropertiesDriver');
        $this->getBean('dingMessageSourceDriver');
        $this->getBean('dingMethodInjectionDriver');

        // All set, continue.
        if (isset(self::$_options['bdef']['annotation'])) {
            $this->getBean('dingAnnotationDiscovererDriver');
            $this->getBean('dingAnnotationBeanDefinitionProvider');
            $this->getBean('dingAnnotationValueDriver');
            $this->getBean('dingAnnotationResourceDriver');
            $this->getBean('dingAnnotationInjectDriver');
            $this->getBean('dingAnnotationInitDestroyMethodDriver');
            $this->getBean('dingAnnotationRequiredDriver');
            $this->getBean('dingMvcAnnotationDriver');
        }
        $this->_lifecycleManager->afterConfig();
    }
}


<?php
/**
 * Simple memcache implementation that uses memcached extension from php:
 * http://www.php.net/manual/en/book.memcached.php
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Cache
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Cache\Impl;
use Ding\Cache\ICache;

/**
 * Simple memcache implementation that uses memcached extension from php:
 * http://www.php.net/manual/en/book.memcached.php
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Cache
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 */
class MemcachedCacheImpl implements ICache
{
    /**
     * Holds current instance.
     * @var MemcachedCacheImpl
     */
    private static $_instance = false;

    /**
     * A Memcached object.
     * @Memcached
     */
    private $_memcached;

    /**
     * Returns a cached value.
     *
     * @param string  $name    Key to look for.
     * @param boolean &$result True on success, false otherwise.
     *
     * @return mixed
     */
    public function fetch($name, &$result)
    {
        $result = false;
        $value = $this->_memcached->get($name);
        if ($this->_memcached->getResultCode() != \Memcached::RES_SUCCESS) {
            return false;
        }
        $result = true;
        return $value;
    }

    /**
     * Stores a key/value.
     *
     * @param string $name  Key to use.
     * @param mixed  $value Value.
     *
     * @return boolean
     */
    public function store($name, $value)
    {
        return $this->_memcached->set($name, $value);
    }

    /**
     * Empties the cache.
     *
	 * @return boolean
     */
    public function flush()
    {
        return $this->_memcached->flush();
    }

    /**
     * Removes a key from the cache.
     *
     * @param string $name Key to remove.
     *
     * @return boolean
     */
    public function remove($name)
    {
        return $this->_memcached->delete($name);
    }

    /**
     * Returns an instance of a cache.
     *
     * @param array $options Options for the cache backend.
     *
     * @return MemcachedCacheImpl
     */
    public static function getInstance($options = array())
    {
        if (self::$_instance == false) {
            self::$_instance = new MemcachedCacheImpl($options);
        }
        return self::$_instance;
    }

    /**
     * Constructor.
     *
	 * @return void
     */
    private function __construct(array $options)
    {
        $this->_memcached = new \Memcached();
        $this->_memcached->addServer($options['host'], $options['port']);
    }
}


<?php
/**
 * Used as an argument to invoke the advice, so you can have all the details
 * about the invoked (aspected) method. In other words, your advice will be
 * invoked with an instance of this class as an argument.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Aspect
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Aspect;

/**
 * Used as an argument to invoke the advice, so you can have all the details
 * about the invoked (aspected) method. In other words, your advice will be
 * invoked with an instance of this class as an argument.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Aspect
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 */
use Ding\Reflection\IReflectionFactory;

class MethodInvocation
{
    /**
     * Class name for the invoked (and aspected) method.
     * @var string
     */
    private $_class;

    /**
     * Name for the invoked (and aspected) method.
     * @var string
     */
    private $_method;

    /**
     * Arguments used to invoke the aspected method.
     * @var array
     */
    private $_args;

    /**
     * Aspected method result.
     * @var mixed
     */
    private $_result;

    /**
     * Exception thrown by the target method.
     */
    private $_exception;

    /**
     * ReflectionFactory implementation.
     * @var IReflectionFactory
     */
    private $_reflectionFactory;

    /**
     * Original invocation.
     * In the case of a chained aspect call, getArguments() and alike, will
     * give you information about the calling aspect, and not the method
     * aspected itself (unless you are the last one in the chain). In order
     * to access information for the original request
     * @see MethodInvocation::getOriginalInvocation()
     * @var MethodInvocation
     */
    private $_originalInvocation;

    /**
     * This invocation will be called onto this object.
     * @var object
     */
    private $_object;

    /**
     * Returns information about the original invocation to the (aspected)
     * method. Will return itself as the original invocation if none was set
     * at construction time.
     *
     * @see MethodInvocation::$_originalInvocation
     *
     * @return MethodInvocation
     */
    public function getOriginalInvocation()
    {
        return
            $this->_originalInvocation == null
            ? $this
            : $this->_originalInvocation
        ;
    }

    /**
     * Call this one *from* your aspect, in order to proceed with the
     * execution. If you pass any arguments to this method, they will override
     * the original arguments when proceeding to the call.
     *
	 * @return void
     */
    public function proceed()
    {
        $target = $this->_reflectionFactory->getMethod($this->_class, $this->_method);
        if (!$target->isPublic()) {
            $target->setAccessible(true);
        }
        $arguments = func_get_args();
        if (empty($arguments)) {
            $arguments = $this->_args;
        }
        $this->_result = $target->invokeArgs($this->_object, $arguments);
        return $this->_result;
    }

    /**
     * If the target method throws an exception, you can get it here.
     *
	 * @return Exception
     */
    public function getException()
    {
        return $this->_exception;
    }

    /**
     * Changes (updates) the exception for the execution of the aspected method.
     *
     * @param Exception $value
     *
     * @return void
     */
    public function setException(\Exception $exception)
    {
        $this->_exception = $exception;
    }

    /**
     * Returns class name for the executed method.
     *
     * @return string
     */
    public function getClass()
    {
        return $this->_class;
    }

    /**
     * Returns name for the executed method.
     *
     * @return string
     */
    public function getMethod()
    {
        return $this->_method;
    }

    /**
     * Returns the target object for this method
     *
     * @return object
     */
    public function getObject()
    {
        return $this->_object;
    }

    /**
     * Returns arguments for the executed method.
     *
     * @return array
     */
    public function getArguments()
    {
        return $this->_args;
    }

    /**
     * Constructor.
     *
     * @param string           $class   Class for the aspected method invoked.
     * @param string           $method  Aspected method invoked.
     * @param array            $args    Arguments used to invoke the aspected
     * method.
     * @param mixed            $result  Result from the execution of the
     * aspected method.
     * @param object           $object  Target invocation object for method.
     * @param IReflectionFactory $reflectionFactory Reflection Factory to use.
     * @param MethodInvocation &$invoke In a chained aspect call, this will
     * be the access to the original (aspected) method call.
     *
     * @see MethodInvocation::getOriginalInvocation()
     * @return void
     */
    public function __construct(
        $class, $method, $args, $object, IReflectionFactory $reflectionFactory,
        MethodInvocation &$invoke = null
    ) {
        $this->_class = $class;
        $this->_method = $method;
        $this->_args = $args;
        $this->_object = $object;
        $this->_originalInvocation = $invoke;
        $this->_reflectionFactory = $reflectionFactory;
    }
}


<?php
/**
 * Smarty view render.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Mvc
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Mvc\Http;

use Ding\Mvc\IViewRender;
use Ding\Mvc\View;

/**
 * Smarty view render.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Mvc
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 */
class SmartyViewRender implements IViewRender
{
    /**
     * Smarty options.
     * @var string[]
     */
    private $_smartyOptions = array();

    /**
     * Sets Smarty options.
     *
     * @param string[] $options Smarty options.
     *
     * @return void
     */
    public function setSmartyOptions(array $options)
    {
        $this->_smartyOptions = $options;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Mvc.IViewRender::render()
     */
    public function render(View $view)
    {
        /**
         * @todo is there a better way to do this?
         */
        global $modelAndView;
        $modelAndView = $view->getModelAndView();
        require_once('Smarty.class.php');
        $smarty = new \Smarty();
        $smarty->template_dir = dirname($view->getPath());
        $smarty->compile_dir = $this->_smartyOptions['compile_dir'];
        $smarty->config_dir = $this->_smartyOptions['config_dir'];
        $smarty->cache_dir = $this->_smartyOptions['cache_dir'];
        $smarty->debugging = $this->_smartyOptions['debugging'];
        foreach ($modelAndView->getModel() as $key => $value) {
            $smarty->assign($key, $value);
        }
        $smarty->display(basename($view->getPath()));
    }
}


<?php
/**
 * Simple apc cache implementation.
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Cache
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Cache\Impl;
use Ding\Cache\ICache;

/**
 * Simple apc cache implementation.
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Cache
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 */
class ApcCacheImpl implements ICache
{
    /**
     * Holds current instance.
     * @var ApcCacheImpl
     */
    private static $_instance = false;

    /**
     * Returns a cached value.
     *
     * @param string  $name    Key to look for.
     * @param boolean &$result True on success, false otherwise.
     *
     * @return mixed
     */
    public function fetch($name, &$result)
    {
        return apc_fetch($name, $result);
    }

    /**
     * Stores a key/value.
     *
     * @param string $name  Key to use.
     * @param mixed  $value Value.
     *
     * @return boolean
     */
    public function store($name, $value)
    {
        return apc_store($name, $value);
    }

    /**
     * Empties the cache.
     *
	 * @return boolean
     */
    public function flush()
    {
        return apc_clear_cache();
    }

    /**
     * Removes a key from the cache.
     *
     * @param string $name Key to remove.
     *
     * @return boolean
     */
    public function remove($name)
    {
        return apc_delete($name);
    }

    /**
     * Returns an instance of a cache.
     *
     * @param array $options Options for the cache backend.
     *
     * @return ApcCacheImpl
     */
    public static function getInstance($options = array())
    {
        if (self::$_instance == false) {
            self::$_instance = new ApcCacheImpl;
        }
        return self::$_instance;
    }

    /**
     * Constructor.
     *
	 * @return void
     */
    private function __construct()
    {
    }
}


<?php
/**
 * This driver will look up all annotations for the class and each method of
 * the class (of the bean, of course).
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Bean
 * @subpackage Provider
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Bean\Provider;

use Ding\Aspect\AspectDefinition;
use Ding\Aspect\PointcutDefinition;
use Ding\Aspect\AspectManager;
use Ding\Aspect\IAspectProvider;
use Ding\Aspect\IAspectManagerAware;
use Ding\Annotation\Collection;
use Ding\Annotation\Annotation as AnnotationDefinition;
use Ding\Reflection\IReflectionFactoryAware;
use Ding\Container\IContainerAware;
use Ding\Bean\IBeanDefinitionProvider;
use Ding\Container\IContainer;
use Ding\Bean\BeanDefinition;
use Ding\Bean\BeanPropertyDefinition;
use Ding\Reflection\IReflectionFactory;
use Ding\Bean\Factory\Exception\BeanFactoryException;

/**
 * This driver will look up all annotations for the class and each method of
 * the class (of the bean, of course).
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Bean
 * @subpackage Factory.Driver
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 */
class Annotation
    implements IBeanDefinitionProvider,
    IContainerAware, IReflectionFactoryAware, IAspectManagerAware, IAspectProvider
{
    protected $container;

    /**
     * Target directories to scan for annotated classes.
     * @var string[]
     */
    private $_scanDirs;

    /**
     * @Configuration annotated classes.
     * @var string[]
     */
    private $_configClasses = false;

    /**
     * @Configuration beans (coming from @Configuration annotated classes).
     * @var object[]
     */
    private $_configBeans = false;

    /**
     * Our cache.
     * @var ICache
     */
    private $_cache = false;

    /**
     * Definitions for config beans.
     * @var BeanDefinition[]
     */
    private $_beanDefinitions = array();

    /**
     * Container.
     * @var IContainer
     */
    private $_container;

    /**
     * A ReflectionFactory implementation.
     * @var IReflectionFactory
     */
    protected $reflectionFactory;

    /**
     * All known beans, indexed by name.
     * @var string[]
     */
    private $_knownBeans = array();
    /**
     * Maps beans from their classes.
     * @var string[]
     */
    private $_knownBeansByClass = array();

    /**
     * This one helps map a bean with a its parent class bean definition.
     * @var string[]
     */
    private $_knownClassesWithValidBeanAnnotations = array();

    /**
     * All beans (names) listening for events will be here.
     * @var string[]
     */
    private $_knownBeansPerEvent = array();

    /**
     * Valid bean annotations.
     * @var string[]
     */
    private $_validBeanAnnotations = array(
    	'controller', 'bean', 'component', 'configuration', 'aspect', 'named'
    );

    private $_aspectManager;

    public function setAspectManager(AspectManager $aspectManager)
    {
        $this->_aspectManager = $aspectManager;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Reflection.IReflectionFactoryAware::setReflectionFactory()
     */
    public function setReflectionFactory(IReflectionFactory $reflectionFactory)
    {
        $this->reflectionFactory = $reflectionFactory;
    }

    /**
     * Returns the bean definition for a parent class of a class (if found). If
     * the parent class has a valid bean annotation (see $_knownBeans) it will
     * be returned.
     *
     * @param string $class
     *
     * @return BeanDefinition|null
     */
    private function _getParentBeanDefinition($class)
    {
        $def = null;
        while($parentRefClass = $this->reflectionFactory->getClass($class)->getParentClass())
        {
            $class = $parentRefClass->getName();
            // Does this class has a valid bean annotation?
            if (isset($this->_knownClassesWithValidBeanAnnotations[$class])) {
                $parentNameBean = $this->_knownClassesWithValidBeanAnnotations[$class];
                return $this->_container->getBeanDefinition($parentNameBean);
            }
        }
        return $def;
    }
    /**
     * Creates a bean definition from the given annotations.
     *
     * @param string $name Bean name.
     * @param string $class Bean class.
     * @param Collection $annotations Annotations with data.
     *
     * @return BeanDefinition
     */
    private function _getBeanDefinition($name, $class, Collection $annotations, $fBean = false, $fMethod = false)
    {
        $def = $this->_getParentBeanDefinition($class);
        if ($def === null) {
            $def = new BeanDefinition($name);
        } else {
            $def = $def->makeChildBean($name);
        }
        if ($fBean) {
            $def->setFactoryBean($fBean);
            $def->setFactoryMethod($fMethod);
        }
        $rClass = $this->reflectionFactory->getClass($class);
        if ($rClass->isAbstract()) {
            $def->makeAbstract();
        } else {
            $def->makeConcrete();
        }
        $def->setClass($class);
        foreach ($this->_validBeanAnnotations as $beanAnnotationName) {
            if ($annotations->contains($beanAnnotationName)) {
                $beanAnnotation = $annotations->getSingleAnnotation($beanAnnotationName);
                break;
            }
        }
        if ($beanAnnotation->hasOption('class')) {
            $def->setClass($beanAnnotation->getOptionSingleValue('class'));
        }
        if ($beanAnnotation->hasOption('name')) {
            $names = $beanAnnotation->getOptionValues('name');
            foreach ($names as $alias) {
                $def->addAlias($alias);
            }
        }
        $def->setName($name);
        if ($annotations->contains('scope')) {
            $annotation = $annotations->getSingleAnnotation('scope');
            if ($annotation->hasOption('value')) {
                $scope = $annotation->getOptionSingleValue('value');
                if ($scope == 'singleton') {
                    $def->setScope(BeanDefinition::BEAN_SINGLETON);
                } else if ($scope == 'prototype') {
                    $def->setScope(BeanDefinition::BEAN_PROTOTYPE);
                } else {
                    throw new BeanFactoryException("Invalid bean scope: $scope");
                }
            }
        } else if ($annotations->contains('singleton')) {
            $def->setScope(BeanDefinition::BEAN_SINGLETON);
        } else if ($annotations->contains('prototype')) {
            $def->setScope(BeanDefinition::BEAN_PROTOTYPE);
        }
        $isPrimary = $annotations->contains('primary');
        if (!$isPrimary) {
            if ($beanAnnotation->hasOption('primary')) {
                $isPrimary = $beanAnnotation->getOptionSingleValue('primary') == 'true';
            }
        }
        if ($isPrimary) {
            $def->markAsPrimaryCandidate();
        }
        if ($annotations->contains('initmethod')) {
            $annotation = $annotations->getSingleAnnotation('initmethod');
            if ($annotation->hasOption('method')) {
                $def->setInitMethod($annotation->getOptionSingleValue('method'));
            }
        }
        if ($annotations->contains('destroymethod')) {
            $annotation = $annotations->getSingleAnnotation('destroymethod');
            if ($annotation->hasOption('method')) {
                $def->setDestroyMethod($annotation->getOptionSingleValue('method'));
            }
        }
        return $def;
    }

    /**
     * Returns all possible names for a bean. If none are found in the bean
     * annotation, the optional $overrideWithName will be chosen. If not, one
     * will be generated.
     *
     * @param AnnotationDefinition $beanAnnotation
     * @param string $overrideWithName
     *
     * @return string[]
     */
    private function _getAllNames(AnnotationDefinition $beanAnnotation, $overrideWithName = false)
    {
        if ($beanAnnotation->hasOption('name')) {
            return $beanAnnotation->getOptionValues('name');
        }
        if ($overrideWithName !== false) {
            return array($overrideWithName);
        }
        return array(BeanDefinition::generateName('Bean'));
    }

    /**
     * Adds a bean to $_knownBeans.
     *
     * @param string $class The class for this bean
     * @param string $key Where this bean has been chosen from (i.e: component, configuration, bean, etc)
     * @param Ding\Annotation\Collection $annotations Annotations for this bean
     * @param string $overrideWithName Override this bean name with this one
     * @param string $fBean An optional factory bean
     * @param string $fMethod An optional factory method
     *
     * @return string The name of the bean recently added
     */
    private function _addBean($class, $key, $annotations, $overrideWithName = false, $fBean = false, $fMethod = false)
    {
        $annotation = $annotations->getSingleAnnotation($key);
        $names = $this->_getAllNames($annotation, $overrideWithName);
        $leadName = $names[0];
        $this->_addBeanToKnownByClass($class, $leadName);
        $this->_knownBeans[$leadName] = array($names, $class, $key, $annotations, $fBean, $fMethod);

        // Dont let @Bean methods interfere with bean parentship.
        if (!$fBean) {
            $this->_knownClassesWithValidBeanAnnotations[$class] = $leadName;
        }
        return $leadName;
    }

    private function _addBeanToKnownByClass($class, $name)
    {
        if (!isset($this->_knownBeansByClass[$class])) {
            $this->_knownBeansByClass[$class] = array();
        }
        $this->_knownBeansByClass[$class][] = $name;
        // Load any parent classes
        $rClass = $this->reflectionFactory->getClass($class);
        $parentClass = $rClass->getParentClass();
        while ($parentClass) {
            $parentClassName = $parentClass->getName();
            $this->_knownBeansByClass[$parentClassName][] = $name;
            $parentClass = $parentClass->getParentClass();
        }

        // Load any interfaces
        foreach ($rClass->getInterfaces() as $interfaceName => $rInterface) {
            $this->_knownBeansByClass[$interfaceName][] = $name;
        }
    }

    private function _traverseConfigClassesAndRegisterForEvents($key, array $configClasses)
    {
        foreach ($configClasses as $class) {
            $rClass = $this->reflectionFactory->getClass($class);
            $annotations = $this->reflectionFactory->getClassAnnotations($class);
            $fBean = $this->_addBean($class, $key, $annotations);
            foreach ($rClass->getMethods() as $method) {
                $methodBeanName = $method->getName();
                $methodBeanAnnotations = $this->reflectionFactory->getMethodAnnotations($class, $methodBeanName);
                if ($methodBeanAnnotations->contains('bean')) {
                    $beanClass = 'stdClass';
                    $beanAnnotation = $methodBeanAnnotations->getSingleAnnotation('bean');
                    if ($beanAnnotation->hasOption('class')) {
                        $beanClass = $beanAnnotation->getOptionSingleValue('class');
                    }
                    $this->_addBean($beanClass, 'bean', $methodBeanAnnotations, $methodBeanName, $fBean, $methodBeanName);
                }
            }
        }
    }

    public function init()
    {
        foreach ($this->_validBeanAnnotations as $beanAnnotationName) {
            $this->_traverseConfigClassesAndRegisterForEvents(
                $beanAnnotationName,
                $this->reflectionFactory->getClassesByAnnotation($beanAnnotationName)
            );
        }
        foreach ($this->_knownBeans as $leadName => $data) {
            $names = $data[0];
            $class = $data[1];
            $key = $data[2];
            $annotations = $data[3];
            $this->registerEventsFor($annotations, $leadName, $class);
        }
    }
    public function getAspects()
    {
        $ret = array();
        $aspectClasses = $this->reflectionFactory->getClassesByAnnotation('aspect');
        foreach ($aspectClasses as $aspectClass) {
            foreach ($this->_knownBeansByClass[$aspectClass] as $beanName) {
                $rClass = $this->reflectionFactory->getClass($aspectClass);
                foreach ($rClass->getMethods() as $rMethod) {
                    $methodName = $rMethod->getName();
                    $annotations = $this->reflectionFactory->getMethodAnnotations($aspectClass, $methodName);
                    if ($annotations->contains('methodinterceptor')) {
                        foreach ($annotations->getAnnotations('methodinterceptor') as $annotation) {
                            $classExpression = $annotation->getOptionSingleValue('class-expression');
                            $expression = $annotation->getOptionSingleValue('expression');
                            $ret[] = $this->_newAspect(
                                $beanName, $classExpression, $expression, $methodName, AspectDefinition::ASPECT_METHOD
                            );

                        }
                    }
                    if ($annotations->contains('exceptioninterceptor')) {
                        foreach ($annotations->getAnnotations('exceptioninterceptor') as $annotation) {
                            $classExpression = $annotation->getOptionSingleValue('class-expression');
                            $expression = $annotation->getOptionSingleValue('expression');
                            $ret[] = $this->_newAspect(
                                $beanName, $classExpression, $expression, $methodName, AspectDefinition::ASPECT_EXCEPTION
                            );
                        }
                    }
                }
            }
        }
        return $ret;
    }

    private function _newAspect($aspectBean, $classExpression, $expression, $method, $type)
    {
        $pointcutName = BeanDefinition::generateName('PointcutAnnotationAspectDriver');
        $pointcutDef = new PointcutDefinition($pointcutName, $expression, $method);
        $aspectName = BeanDefinition::generateName('AnnotationAspected');
        $aspectDef = new AspectDefinition(
            $aspectName, array($pointcutName), $type,
            $aspectBean, $classExpression
        );
        $this->_aspectManager->setPointcut($pointcutDef);
        return $aspectDef;
    }

    /**
     * Looks for @ListensOn and register the bean as an event listener. Since
     * this is an "early" discovery of a bean, a BeanDefinition is generated.
     *
     * @param Collection $annotations Bean Annotations (for classes or methods)
     * @param string $beanName The target bean name.
     * @param string $class The bean class
     *
     * @return void
     */
    protected function registerEventsFor(Collection $annotations, $beanName, $class)
    {
        $rClass = $this->reflectionFactory->getClass($class);
        if ($rClass->isAbstract()) {
            return;
        }
        $this->_registerEventsForBeanName($annotations, $beanName);
        while($rClass = $this->reflectionFactory->getClass($class)->getParentClass()) {
            $class = $rClass->getName();
            $annotations = $this->reflectionFactory->getClassAnnotations($rClass->getName());
            $this->_registerEventsForBeanName($annotations, $beanName);
        }
    }

    private function _registerEventsForBeanName(Collection $annotations, $beanName)
    {
        if ($annotations->contains('listenson')) {
            $annotation = $annotations->getSingleAnnotation('listenson');
            foreach ($annotation->getOptionValues('value') as $eventCsv) {
                foreach (explode(',', $eventCsv) as $eventName) {
                    if (!isset($this->_knownBeansPerEvent[$eventName])) {
                        $this->_knownBeansPerEvent[$eventName] = array();
                    }
                    $this->_knownBeansPerEvent[$eventName][] = $beanName;
                }
            }
        }
    }
    /**
     * (non-PHPdoc)
     * @see Ding\Bean.IBeanDefinitionProvider::getBeansListeningOn()
     */
    public function getBeansListeningOn($eventName)
    {
        if (isset($this->_knownBeansPerEvent[$eventName])) {
            return $this->_knownBeansPerEvent[$eventName];
        }
        return array();
    }
    /**
     * (non-PHPdoc)
     * @see Ding\Aspect.IBeanDefinitionProvider::getBeanDefinition()
     */
    public function getBeanDefinition($name)
    {
        foreach ($this->_knownBeans as $leadName => $data) {

            $names = $data[0];
            $class = $data[1];
            $key = $data[2];
            $annotations = $data[3];
            $fBean = $data[4];
            $fMethod = $data[5];
            if (in_array($name, $names)) {
                return $this->_getBeanDefinition($name, $class, $annotations, $fBean, $fMethod);
            }
        }
        return null;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Aspect.IBeanDefinitionProvider::getBeanDefinitionByClass()
     */
    public function getBeansByClass($class)
    {
        if (isset($this->_knownBeansByClass[$class])) {
            return $this->_knownBeansByClass[$class];
        }
        return array();
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Container.IContainerAware::setContainer()
     */
    public function setContainer(IContainer $container)
    {
        $this->_container = $container;
    }

    public function setCache(\Ding\Cache\ICache $cache)
    {
        $this->_cache = $cache;
    }
    /**
     * Constructor.
     *
     * @param array              $options Optional options.
     * @param \Ding\Cache\ICache $cache   Annotations cache.
     *
     * @return void
     */
    public function __construct(array $options)
    {
        $this->_scanDirs = $options['scanDir'];
        $this->_configClasses = array();
        $this->_beanDefinitions = array();
        $this->_configBeans = array();
    }
}


<?php
/**
 * Ding autoloader, you will surely need this.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Autoloader
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Autoloader;

/**
 * Ding autoloader, you will surely need this.
 *
 * PHP Version 5
 *
 * @category Ding
 * @package  Autoloader
 * @author   Marcelo Gornstein <marcelog@gmail.com>
 * @license  http://marcelog.github.com/ Apache License 2.0
 * @link     http://marcelog.github.com/
 */
class Autoloader
{
    /**
     * Called by php to load a given class. Returns true if the class was
     * successfully loaded.
     *
     * @return boolean
     */
    public static function load($class)
    {
        $classFile = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
        $file = stream_resolve_include_path($classFile);
        if ($file && file_exists($file)) {
            require_once $file;
            return true;
        }
        return false;
    }

    /**
     * You need to use this function to autoregister this loader.
     *
     * @see spl_autoload_register()
     *
     * @return boolean
     */
    public static function register()
    {
        return spl_autoload_register('\Ding\Autoloader\Autoloader::load');
    }
}


<?php
/**
 * A generic url resource. All php scheme's are supported.
 * See http://www.php.net/manual/en/wrappers.php
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Resource
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
namespace Ding\Resource\Impl;

use Ding\Resource\Exception\ResourceException;
use Ding\Resource\IResource;

/**
 * A generic url resource. All php scheme's are supported.
 * See http://www.php.net/manual/en/wrappers.php
 *
 * PHP Version 5
 *
 * @category   Ding
 * @package    Resource
 * @subpackage Impl
 * @author     Marcelo Gornstein <marcelog@gmail.com>
 * @license    http://marcelog.github.com/ Apache License 2.0
 * @link       http://marcelog.github.com/
 *
 * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
class URLResource implements IResource
{
    /**
     * Holds true filename.
     * @var string
     */
    private $_filename;

    /**
     * Holds file resource.
     * @var stream
     */
    private $_fd;

    /**
     * Holds scheme.
     * @var string
     */
    private $_scheme;

    /**
     * Holds context, created with stream_context_create()
     * @var resource
     */
    private $_context;

    /**
     * URL data from parse_url
     * @var string[]
     */
    private $_urlData;

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResource::exists()
     */
    public function exists()
    {
        try
        {
            $stream = $this->getStream();
            return $stream !== false;
        } catch(ResourceException $exception) {
        }
        return false;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResource::isOpen()
     */
    public function isOpen()
    {
        return $this->_fd !== false;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResource::getURL()
     */
    public function getURL()
    {
        return $this->_filename;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResource::getStream()
     */
    public function getStream()
    {
        if ($this->_fd === false) {
            $this->_fd
                = $this->_context === false
                ? @fopen($this->_filename, 'r', false)
                : @fopen($this->_filename, 'r', false, $this->_context);
            if ($this->_fd === false) {
                throw new ResourceException('Could not open: ' . $this->_filename);
            }
        }
        return $this->_fd;
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResource::createRelative()
     */
    public function createRelative($relativePath)
    {
       return new URLResource($this->_filename . DIRECTORY_SEPARATOR . $relativePath);
    }

    /**
     * (non-PHPdoc)
     * @see Ding\Resource.IResource::getFilename()
     */
    public function getFilename()
    {
        return $this->_urlData['path'];
    }

    /**
     * Constructor.
     *
     * @param string $filename Filename with or without includepath://.
     * @param resource $context  Context created with stream_context_create().
     *
     * @return void
     */
    public function __construct($filename, $context = false)
    {
        $this->_urlData = parse_url($filename);
        if ($this->_urlData === false) {
            throw new ResourceException('Invalid url: ' . $filename);
        }
        if (!isset($this->_urlData['scheme'])) {
            throw new ResourceException('Invalid url: ' . $filename);
        }
        $this->_filename = $filename;
        $this->_scheme = $this->_urlData['scheme'];
        $this->_fd = false;
        $this->_context = $context;
    }
}