taviroquai/duality

View on GitHub
src/Duality/App.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php

/**
 * High level application container (DIC)
 *
 * PHP Version 5.3.4
 *
 * @author  Marco Afonso <mafonso333@gmail.com>
 * @license http://opensource.org/licenses/MIT MIT
 * @link    http://github.com/taviroquai/duality
 * @since   0.7.0
 */

namespace Duality;

use Duality\Core\DualityException;
use Duality\Core\Container;
use Duality\Core\AbstractService;
use Duality\Structure\Storage;
use Duality\Structure\File\StreamFile;

/**
 * Default application container
 *
 * PHP Version 5.3.4
 *
 * @author  Marco Afonso <mafonso333@gmail.com>
 * @license http://opensource.org/licenses/MIT MIT
 * @link    http://github.com/taviroquai/duality
 * @since   0.7.0
 */
class App 
extends Container
{
    /**
     * Holds application working directory
     * 
     * @var string The base path of the application
     */
    protected $path;

    /**
     * Holds environment configuration
     * 
     * @var array The original configuration
     */
    protected $config;

    /**
     * Container cache
     * 
     * @var \Duality\Core\InterfaceStorage The cache storage
     */
    protected $cache;
    
    /**
     * Holds the application output buffer
     * 
     * @var \Duality\File\StreamFile The output buffer
     */
    protected $buffer;

    /**
     * Setup default services
     * 
     * @var array The default Duality services
     */
    protected $defaults = array(
        'db'        => 'Duality\Service\Database\SQLite',
        'logger'    => 'Duality\Service\Logger',
        'security'  => 'Duality\Service\Security',
        'validator' => 'Duality\Service\Validator',
        'session'   => 'Duality\Service\Session\Dummy',
        'auth'      => 'Duality\Service\Auth\Database',
        'cache'     => 'Duality\Service\Cache\APC',
        'mailer'    => 'Duality\Service\Mailer',
        'paginator' => 'Duality\Service\Paginator',
        'remote'    => 'Duality\Service\SSH',
        'server'    => 'Duality\Service\Server',
        'locale'    => 'Duality\Service\Localization',
        'cmd'       => 'Duality\Service\Commander',
        'client'    => 'Duality\Service\Client',
        'performance' => 'Duality\Service\Performance'
    );

    /**
     * Create a new application
     * 
     * @param string $path   Give the base path to resolve relative paths
     * @param array  $config Give the configuration as array
     */
    public function __construct($path, $config = array())
    {
        if (!is_dir($path)) {
            throw new DualityException(
                "Error Application: path not found",
                DualityException::E_APP_PATHNOTFOUND
            );
        }
        $this->path = (string) $path;

        $config['services'] = empty($config['services']) ?
            $this->defaults : array_merge($this->defaults, $config['services']);
        $this->config = (array) $config;

        $this->services = new Storage;
        $this->services->reset();
        $this->cache = new Storage;
        $this->cache->reset();

        $bufferType = $this->getConfigItem('buffer') ? 
            $this->getConfigItem('buffer') : 'php://output';
        $this->buffer = new StreamFile($bufferType);
        $this->buffer->open();
    }

    /**
     * Terminate services and close buffer (if exists)
     * 
     * @return void
     */
    public function __destruct()
    {
        foreach ($this->cache->asArray() as $name => $service) {
            $instance = $this->call($name);
            if ($instance instanceof AbstractService) {
                call_user_func(array($instance, 'terminate'));
            }
        }
        $this->getBuffer()->close();
    }

    /**
     * Add common services
     * 
     * @param string $name Give the name to load the service
     * 
     * @return void
     */
    protected function loadService($name)
    {
        $me =& $this;

        // Register and init service
        $class = $this->config['services'][$name];
        $this->register(
            $name, function () use ($class, $me) {
                $instance = new $class($me);
                return $instance;
            }
        );
        $service = $this->call($name);
        if (is_a($service, 'Duality\Core\AbstractService', true)) {
            $service->init();
        }
    }

    /**
     * Returns application path
     * 
     * @return string The base path to resolve relative paths
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Returns environment configuration
     * 
     * @return array The original configuration
     */
    public function getConfig()
    {
        return $this->config;
    }
    
    /**
     * Returns application output buffer
     * 
     * @return \Duality\File\StreamFile The output buffer
     */
    public function getBuffer()
    {
        return $this->buffer;
    }

    /**
     * Returns environment configuration
     * 
     * @param string $path Give the path, ie. mailer.smtp.pass
     * 
     * @return mixed|null The result value or null
     */
    public function getConfigItem($path)
    {
        $parts = explode('.', $path);
        $result = $this->config;
        foreach ($parts as $item) {
            if (!isset($result[$item])) {
                return null;
            }
            $result = $result[$item];
        }
        return $result;
    }

    /**
     * Register service
     * 
     * @param string   $name    Give a name to the service
     * @param \Closure $service Give the service callback
     * 
     * @return \Duality\App This instance
     */
    public function register($name, \Closure $service)
    {
        $this->services->set($name, $service);
        return $this;
    }

    /**
     * Checks wether exists a regitered service name
     * 
     * @param string $name Give a name to check if service exists
     * 
     * @return boolean The check result
     */
    public function exists($name)
    {
        return $this->cache->has($name);
    }

    /**
     * Call service
     * 
     * @param string  $name   Give a name to identify the service
     * @param array   $params Give the parameters to pass
     * @param boolean $cache  Tell whether to cache the callback result or not
     * 
     * @return mixed The service callback result
     */
    public function call($name, $params = array(), $cache = true)
    {
        if (!$this->services->has($name)
            && isset($this->config['services'][$name])
        ) {
            $this->loadService($name);
        }
        if ($cache) {
            if (!$this->exists($name)) {
                $this->cache->set(
                    $name, call_user_func_array($this->services->get($name), $params)
                );
            }
            return $this->cache->get($name);
        }
        return call_user_func_array($this->services->get($name), $params);
    }

    /**
     * Call database service alias (type hinting)
     * 
     * @return \Duality\Service\Database The database service
     */
    public function getDb()
    {
        return $this->call('db');
    }

    /**
     * Call logger service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceErrorHandler The logger service
     */
    public function getLogger()
    {
        return $this->call('logger');
    }

    /**
     * Call security service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceSecurity The security service
     */
    public function getSecurity()
    {
        return $this->call('security');
    }

    /**
     * Call validator service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceValidator The validator service
     */
    public function getValidator()
    {
        return $this->call('validator');
    }

    /**
     * Call session service alias (type hinting)
     * 
     * @return \Duality\Service\Session The session service
     */
    public function getSession()
    {
        return $this->call('session');
    }

    /**
     * Call auth service alias (type hinting)
     * 
     * @return \Duality\Service\Auth The auth service
     */
    public function getAuth()
    {
        return $this->call('auth');
    }

    /**
     * Call cache service alias (type hinting)
     * 
     * @return \Duality\Service\Cache The cache service
     */
    public function getCache()
    {
        return $this->call('cache');
    }

    /**
     * Call mailer service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceMailer The mailer service
     */
    public function getMailer()
    {
        return $this->call('mailer');
    }

    /**
     * Call paginator service alias (type hinting)
     * 
     * @return \Duality\Core\InterfacePaginator The paginator service
     */
    public function getPaginator()
    {
        return $this->call('paginator');
    }

    /**
     * Call remote service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceRemote The remote service
     */
    public function getRemote()
    {
        return $this->call('remote');
    }

    /**
     * Call http server service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceServer The server service
     */
    public function getServer()
    {
        return $this->call('server');
    }

    /**
     * Call locale service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceLocalization The localization service
     */
    public function getLocale()
    {
        return $this->call('locale');
    }

    /**
     * Call cmd service alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceCommander The commander service
     */
    public function getCmd()
    {
        return $this->call('cmd');
    }

    /**
     * Call http client alias (type hinting)
     * 
     * @return \Duality\Core\InterfaceClient The http client service
     */
    public function getClient()
    {
        return $this->call('client');
    }

    /**
     * Call performance alias (type hinting)
     * 
     * @return \Duality\Service\Performance The performance service
     */
    public function getPerformance()
    {
        return $this->call('performance');
    }
}