Вход Регистрация
Файл: libs/flight/Engine.php
Строк: 404
<?php
/**
 * Flight: An extensible micro-framework.
 *
 * @copyright   Copyright (c) 2011, Mike Cao <mike@mikecao.com>
 * @license     MIT, http://flightphp.com/license
 */

namespace flight;

use 
flightcoreLoader;
use 
flightcoreDispatcher;

/**
 * The Engine class contains the core functionality of the framework.
 * It is responsible for loading an HTTP request, running the assigned services,
 * and generating an HTTP response.
 */
class Engine {
    
/**
     * Stored variables.
     *
     * @var array
     */
    
protected $vars;

    
/**
     * Class loader.
     *
     * @var object
     */
    
protected $loader;

    
/**
     * Event dispatcher.
     *
     * @var object
     */
    
protected $dispatcher;

    
/**
     * Constructor.
     */
    
public function __construct() {
        
$this->vars = array();

        
$this->loader = new Loader();
        
$this->dispatcher = new Dispatcher();

        
$this->init();
    }

    
/**
     * Handles calls to class methods.
     *
     * @param string $name Method name
     * @param array $params Method parameters
     * @return mixed Callback results
     */
    
public function __call($name$params) {
        
$callback $this->dispatcher->get($name);

        if (
is_callable($callback)) {
            return 
$this->dispatcher->run($name$params);
        }

        
$shared = (!empty($params)) ? (bool)$params[0] : true;

        return 
$this->loader->load($name$shared);
    }

    
/*** Core Methods ***/

    /**
     * Initializes the framework.
     */
    
public function init() {
        static 
$initialized false;
        
$self $this;

        if (
$initialized) {
            
$this->vars = array();
            
$this->loader->reset();
            
$this->dispatcher->reset();
        }

        
// Register default components
        
$this->loader->register('request''flightnetRequest');
        
$this->loader->register('response''flightnetResponse');
        
$this->loader->register('router''flightnetRouter');
        
$this->loader->register('view''flighttemplateView', array(), function($view) use ($self) {
            
$view->path $self->get('flight.views.path');
        });

        
// Register framework methods
        
$methods = array(
            
'start','stop','route','halt','error','notFound',
            
'render','redirect','etag','lastModified','json','jsonp'
        
);
        foreach (
$methods as $name) {
            
$this->dispatcher->set($name, array($this'_'.$name));
        }

        
// Default configuration settings
        
$this->set('flight.base_url'null);
        
$this->set('flight.handle_errors'true);
        
$this->set('flight.log_errors'false);
        
$this->set('flight.views.path''./app/views');

        
$initialized true;
    }

    
/**
     * Enables/disables custom error handling.
     *
     * @param bool $enabled True or false
     */
    
public function handleErrors($enabled)
    {
        if (
$enabled) {
            
set_error_handler(array($this'handleError'));
            
set_exception_handler(array($this'handleException'));
        }
        else {
            
restore_error_handler();
            
restore_exception_handler();
        }
    }

    
/**
     * Custom error handler. Converts errors into exceptions.
     *
     * @param int $errno Error number
     * @param int $errstr Error string
     * @param int $errfile Error file name
     * @param int $errline Error file line number
     * @throws ErrorException
     */
    
public function handleError($errno$errstr$errfile$errline) {
        if (
$errno error_reporting()) {
            throw new 
ErrorException($errstr$errno0$errfile$errline);
        }
    }

    
/**
     * Custom exception handler. Logs exceptions.
     *
     * @param Exception $e Thrown exception
     */
    
public function handleException(Exception $e) {
        if (
$this->get('flight.log_errors')) {
            
error_log($e->getMessage());
        }

        
$this->error($e);
    }

    
/**
     * Maps a callback to a framework method.
     *
     * @param string $name Method name
     * @param callback $callback Callback function
     * @throws Exception If trying to map over a framework method
     */
    
public function map($name$callback) {
        if (
method_exists($this$name)) {
            throw new 
Exception('Cannot override an existing framework method.');
        }

        
$this->dispatcher->set($name$callback);
    }

    
/**
     * Registers a class to a framework method.
     *
     * @param string $name Method name
     * @param string $class Class name
     * @param array $params Class initialization parameters
     * @param callback $callback Function to call after object instantiation
     * @throws Exception If trying to map over a framework method
     */
    
public function register($name$class, array $params = array(), $callback null) {
        if (
method_exists($this$name)) {
            throw new 
Exception('Cannot override an existing framework method.');
        }

        
$this->loader->register($name$class$params$callback);
    }

    
/**
     * Adds a pre-filter to a method.
     *
     * @param string $name Method name
     * @param callback $callback Callback function
     */
    
public function before($name$callback) {
        
$this->dispatcher->hook($name'before'$callback);
    }

    
/**
     * Adds a post-filter to a method.
     *
     * @param string $name Method name
     * @param callback $callback Callback function
     */
    
public function after($name$callback) {
        
$this->dispatcher->hook($name'after'$callback);
    }

    
/**
     * Gets a variable.
     *
     * @param string $key Key
     * @return mixed
     */
    
public function get($key null) {
        if (
$key === null) return $this->vars;

        return isset(
$this->vars[$key]) ? $this->vars[$key] : null;
    }

    
/**
     * Sets a variable.
     *
     * @param mixed $key Key
     * @param string $value Value
     */
    
public function set($key$value null) {
        if (
is_array($key) || is_object($key)) {
            foreach (
$key as $k => $v) {
                
$this->vars[$k] = $v;
            }
        }
        else {
            
$this->vars[$key] = $value;
        }
    }

    
/**
     * Checks if a variable has been set.
     *
     * @param string $key Key
     * @return bool Variable status
     */
    
public function has($key) {
        return isset(
$this->vars[$key]);
    }

    
/**
     * Unsets a variable. If no key is passed in, clear all variables.
     *
     * @param string $key Key
     */
    
public function clear($key null) {
        if (
is_null($key)) {
            
$this->vars = array();
        }
        else {
            unset(
$this->vars[$key]);
        }
    }

    
/**
     * Adds a path for class autoloading.
     *
     * @param string $dir Directory path
     */
    
public function path($dir) {
        
$this->loader->addDirectory($dir);
    }

    
/*** Extensible Methods ***/

    /**
     * Starts the framework.
     */
    
public function _start() {
        
$dispatched false;
        
$self $this;
        
$request $this->request();
        
$response $this->response();
        
$router $this->router();

        
// Flush any existing output
        
if (ob_get_length() > 0) {
            
$response->write(ob_get_clean());
        }

        
// Enable output buffering
        
ob_start();

        
// Enable error handling
        
$this->handleErrors($this->get('flight.handle_errors'));

        
// Disable caching for AJAX requests
        
if ($request->ajax) {
            
$response->cache(false);
        }

        
// Allow post-filters to run
        
$this->after('start', function() use ($self) {
            
$self->stop();
        });

        
// Route the request
        
while ($route $router->route($request)) {
            
$params array_values($route->params);

            
$continue $this->dispatcher->execute(
                
$route->callback,
                
$params
            
);

            
$dispatched true;

            if (!
$continue) break;

            
$router->next();

            
$dispatched false;
        }

        if (!
$dispatched) {
            
$this->notFound();
        }
    }

    
/**
     * Stops the framework and outputs the current response.
     *
     * @param int $code HTTP status code
     */
    
public function _stop($code 200) {
        
$this->response()
            ->
status($code)
            ->
write(ob_get_clean())
            ->
send();
    }

    
/**
     * Stops processing and returns a given response.
     *
     * @param int $code HTTP status code
     * @param string $message Response message
     */
    
public function _halt($code 200$message '') {
        
$this->response(false)
            ->
status($code)
            ->
write($message)
            ->
send();
    }

    
/**
     * Sends an HTTP 500 response for any errors.
     *
     * @param Exception Thrown exception
     */
    
public function _error(Exception $e) {
        
$msg sprintf('<h1>500 Internal Server Error</h1>'.
            
'<h3>%s (%s)</h3>'.
            
'<pre>%s</pre>',
            
$e->getMessage(),
            
$e->getCode(),
            
$e->getTraceAsString()
        );

        try {
            
$this->response(false)
                ->
status(500)
                ->
write($msg)
                ->
send();
        }
        catch (
Exception $ex) {
            exit(
$msg);
        }
    }

    
/**
     * Sends an HTTP 404 response when a URL is not found.
     */
    
public function _notFound() {
        
$this->response(false)
            ->
status(404)
            ->
write(
                
'<h1>404 Not Found</h1>'.
                
'<h3>The page you have requested could not be found.</h3>'.
                
str_repeat(' '512)
            )
            ->
send();
    }

    
/**
     * Routes a URL to a callback function.
     *
     * @param string $pattern URL pattern to match
     * @param callback $callback Callback function
     * @param boolean $pass_route Pass the matching route object to the callback
     */
    
public function _route($pattern$callback$pass_route false) {
        
$this->router()->map($pattern$callback$pass_route);
    }

    
/**
     * Redirects the current request to another URL.
     *
     * @param string $url URL
     * @param int $code HTTP status code
     */
    
public function _redirect($url$code 303) {
        
$base $this->get('flight.base_url');

        if (
$base === null) {
            
$base $this->request()->base;
        }

        
// Append base url to redirect url
        
if ($base != '/' && strpos($url'://') === false) {
            
$url preg_replace('#/+#''/'$base.'/'.$url);
        }

        
$this->response(false)
            ->
status($code)
            ->
header('Location'$url)
            ->
write($url)
            ->
send();
    }

    
/**
     * Renders a template.
     *
     * @param string $file Template file
     * @param array $data Template data
     * @param string $key View variable name
     */
    
public function _render($file$data null$key null) {
        if (
$key !== null) {
            
$this->view()->set($key$this->view()->fetch($file$data));
        }
        else {
            
$this->view()->render($file$data);
        }
    }

    
/**
     * Sends a JSON response.
     *
     * @param mixed $data JSON data
     * @param int $code HTTP status code
     * @param bool $encode Whether to perform JSON encoding
     */
    
public function _json($data$code 200$encode true) {
        
$json = ($encode) ? json_encode($data) : $data;

        
$this->response(false)
            ->
status($code)
            ->
header('Content-Type''application/json')
            ->
write($json)
            ->
send();
    }
    
    
/**
     * Sends a JSONP response.
     *
     * @param mixed $data JSON data
     * @param string $param Query parameter that specifies the callback name.
     * @param int $code HTTP status code
     * @param bool $encode Whether to perform JSON encoding
     */
    
public function _jsonp($data$param 'jsonp'$code 200$encode true) {
        
$json = ($encode) ? json_encode($data) : $data;

        
$callback $this->request()->query[$param];

        
$this->response(false)
            ->
status($code)
            ->
header('Content-Type''application/javascript')
            ->
write($callback.'('.$json.');')
            ->
send();
    }

    
/**
     * Handles ETag HTTP caching.
     *
     * @param string $id ETag identifier
     * @param string $type ETag type
     */
    
public function _etag($id$type 'strong') {
        
$id = (($type === 'weak') ? 'W/' '').$id;

        
$this->response()->header('ETag'$id);

        if (isset(
$_SERVER['HTTP_IF_NONE_MATCH']) &&
            
$_SERVER['HTTP_IF_NONE_MATCH'] === $id) {
            
$this->halt(304);
        }
    }

    
/**
     * Handles last modified HTTP caching.
     *
     * @param int $time Unix timestamp
     */
    
public function _lastModified($time) {
        
$this->response()->header('Last-Modified'date(DATE_RFC1123$time));

        if (isset(
$_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
            
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $time) {
            
$this->halt(304);
        }
    }
}
Онлайн: 1
Реклама