Source

Ray / Ray / Ray.php

<?php

namespace Ray;

/**
 * Ray - micro framework for PHP
 * @author Mateusz Łopaciński <mateusz@robopuff.com> {@link http://robopuff.com}
 * @since 1.0.0
 * @version 1.0.0
 */
class Ray{

    /**
     * Configuration handler
     * @var array
     */
    public  $config;

    /**
     * Routers handler
     * @var Router
     */
    public  $router;

    /**
     * Request handler
     * @var Request
     */
    public  $request;

    /**
     * Response handler
     * @var Response
     */
    public  $response;

    /**
     * Pre/Post Dispatch handler
     * @var array
     */
    public  $dispatch;

    /**
     * Create new great app
     * @param array $config Application configuration
     * @param null $preDispatch Executed before View processing
     * @param null $postDispatch Executed after View, or Error processing
     */
    public function __construct($config=array(), $preDispatch=null, $postDispatch=null){
        spl_autoload_register(array('Ray\Ray', 'autoload'));

        if ( @date_default_timezone_set(date_default_timezone_get()) === false ) {
            date_default_timezone_set('UTC');
        }

        if(!defined('DS')){
            define('DS', DIRECTORY_SEPARATOR);
        }

        if(!defined('ROOT')){
            define('ROOT', realpath(dirname(__FILE__)  . DS . '..' . DS ));
        }

        if(!defined('PATH')){
            if(defined('RAY_PHAR')){
                $path = RAY_PHAR;
            }else{
                $path = ROOT;
            }

            define('PATH', $path);
        }

        $this->config = array_merge(array(
            'mode' => 'production',
            'templates' => ROOT . DS . 'template',
            'view' => 'Ray\View\Inline'
        ), $config);

        if($preDispatch && is_callable($preDispatch)){
            $this->dispatch['pre'] = $preDispatch;
        }

        if($postDispatch && is_callable($postDispatch)){
            $this->dispatch['post'] = $postDispatch;
        }

        $this->router = new Router();

        $this->response = new Response();

        $this->request = new Request();

        $this->response->responseCode(Response::OK);
    }

    /**
     * @param $method
     * @param $args
     * @return array|bool
     * @throws Exception\Call
     */
    public function __call($method, $args){

        $reflection = new \ReflectionObject($this->request);

        $via = 'METHOD_' . strtoupper($method);

        if($reflection->hasConstant($via)){
            return $this->mapRoute($reflection->getConstant($via), $args);
        }else{
            throw new Exception\Call('What the heck is that!? <i>__call('.$method.', '.var_export($args, true).')</i>');
        }
    }

    /**
     * Show it to the world
     */
    public function __destruct(){

        if($this->router){
            if(isset($this->dispatch['pre'])){
                call_user_func($this->dispatch['pre']);
            }

            $return = $this->router->process($this->request->getRequest());

            if($return){
                $viewClass = isset($return['view']) && $return['view'] ? $return['view'] : $this->config['view'];
                $view = new $viewClass($return['callback'], $this->config);
                $send = $view->render();
            }elseif($this->router->hasRoute(Request::METHOD_GET, '/error/404')){
                $response = Response::NOT_FOUND;

                $request = $this->request->getRequest();

                $request->method = Request::METHOD_GET;

                $request->uri = '/error/404';

                $error = $this->router->proccess($request);

                $viewClass = isset($error['view']) && $error['view'] ? $error['view'] : $this->config['view'];

                $view = new $viewClass($error['callback'], $this->config);

                $send =  $view->render();

            }else{
                $response = Response::NOT_FOUND;
                $send = Response::NOT_FOUND;
            }

            if(isset($response)){
                $this->response->responseCode($response);
            }

            if(isset($this->dispatch['post'])){
                call_user_func($this->dispatch['post']);
            }

            $this->response->send($send);
        }
    }

    /**
     * Run application - alias for __destruct()
     */
    public function run(){
        return $this->__destruct();
    }

    /**
     * @param $method
     * @param $args
     * @return array|bool
     */
    private function mapRoute($method, $args){
        if(count($args) >= 2){
            $pattern = $args[0];
            $callable = $args[1];
            $view = isset($args[2]) ? $args[2] : $this->config['view'];

            return $this->router->map($method, $pattern, $callable, $view);
        }

        return false;
    }

    /**
     * Map route
     * @return array|bool
     */
    public function map(){
        $args = func_get_args();
        return $this->mapRoute($args);
    }

    /**
     * Define error handler
     * @param $code
     * @param $callable
     * @param null $view
     */
    public function error($code, $callable, $view=null){
        $this->get('/error/'.$code, $callable, $view);
    }

    /**
     * Autoloader
     * @static
     * @param $class
     */
    public static function autoload( $class ) {
        $file = PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';

        if ( file_exists($file) ) {
            require $file;
        }
    }
}