You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
632 lines
14 KiB
632 lines
14 KiB
<?php
|
|
/**
|
|
* Part of the Fuel framework.
|
|
*
|
|
* @package Fuel
|
|
* @version 1.8
|
|
* @author Fuel Development Team
|
|
* @license MIT License
|
|
* @copyright 2010 - 2016 Fuel Development Team
|
|
* @link http://fuelphp.com
|
|
*/
|
|
|
|
namespace Fuel\Core;
|
|
|
|
/**
|
|
* The Request class is used to create and manage new and existing requests. There
|
|
* is a main request which comes in from the browser or command line, then new
|
|
* requests can be created for HMVC requests.
|
|
*
|
|
* Example Usage:
|
|
*
|
|
* $request = Request::forge('foo/bar')->execute();
|
|
* echo $request->response();
|
|
*
|
|
* @package Fuel
|
|
* @subpackage Core
|
|
*/
|
|
class Request
|
|
{
|
|
/**
|
|
* Holds the main request instance
|
|
*
|
|
* @var Request
|
|
*/
|
|
protected static $main = false;
|
|
|
|
/**
|
|
* Holds the global active request instance
|
|
*
|
|
* @var Request
|
|
*/
|
|
protected static $active = false;
|
|
|
|
/**
|
|
* Generates a new request. The request is then set to be the active
|
|
* request. If this is the first request, then save that as the main
|
|
* request for the app.
|
|
*
|
|
* Usage:
|
|
*
|
|
* Request::forge('hello/world');
|
|
*
|
|
* @param string $uri The URI of the request
|
|
* @param mixed $options Internal: whether to use the routes; external: driver type or array with settings (driver key must be set)
|
|
* @param string $method request method
|
|
* @return Request The new request object
|
|
*/
|
|
public static function forge($uri = null, $options = true, $method = null)
|
|
{
|
|
is_bool($options) and $options = array('route' => $options);
|
|
is_string($options) and $options = array('driver' => $options);
|
|
|
|
if ( ! empty($options['driver']))
|
|
{
|
|
$class = \Inflector::words_to_upper('Request_'.$options['driver']);
|
|
return $class::forge($uri, $options, $method);
|
|
}
|
|
|
|
$request = new static($uri, isset($options['route']) ? $options['route'] : true, $method);
|
|
if (static::$active)
|
|
{
|
|
$request->parent = static::$active;
|
|
static::$active->children[] = $request;
|
|
}
|
|
|
|
// fire any request created events
|
|
\Event::instance()->has_events('request_created') and \Event::instance()->trigger('request_created', '', 'none');
|
|
|
|
return $request;
|
|
}
|
|
|
|
/**
|
|
* Returns the main request instance (the one from the browser or CLI).
|
|
* This is the first executed Request, not necessarily the root parent of the current request.
|
|
*
|
|
* Usage:
|
|
*
|
|
* Request::main();
|
|
*
|
|
* @return Request
|
|
*/
|
|
public static function main()
|
|
{
|
|
return static::$main;
|
|
}
|
|
|
|
/**
|
|
* Returns the active request currently being used.
|
|
*
|
|
* Usage:
|
|
*
|
|
* Request::active();
|
|
*
|
|
* @param Request|null|false $request overwrite current request before returning, false prevents overwrite
|
|
* @return Request
|
|
*/
|
|
public static function active($request = false)
|
|
{
|
|
if ($request !== false)
|
|
{
|
|
static::$active = $request;
|
|
}
|
|
|
|
return static::$active;
|
|
}
|
|
|
|
/**
|
|
* Returns the current request is an HMVC request
|
|
*
|
|
* Usage:
|
|
*
|
|
* if (Request::is_hmvc())
|
|
* {
|
|
* // Do something special...
|
|
* return;
|
|
* }
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_hmvc()
|
|
{
|
|
return ((\Fuel::$is_cli and static::main()) or static::active() !== static::main());
|
|
}
|
|
|
|
/**
|
|
* Reset's the active request with the previous one. This is needed after
|
|
* the active request is finished.
|
|
*
|
|
* Usage:
|
|
*
|
|
* Request::reset_request();
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function reset_request($full = false)
|
|
{
|
|
// Let's make the previous Request active since we are done executing this one.
|
|
static::$active and static::$active = static::$active->parent();
|
|
|
|
if ($full)
|
|
{
|
|
static::$main = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Holds the response object of the request.
|
|
*
|
|
* @var Response
|
|
*/
|
|
public $response = null;
|
|
|
|
/**
|
|
* The Request's URI object.
|
|
*
|
|
* @var Uri
|
|
*/
|
|
public $uri = null;
|
|
|
|
/**
|
|
* The request's route object
|
|
*
|
|
* @var Route
|
|
*/
|
|
public $route = null;
|
|
|
|
/**
|
|
* @var string $method request method
|
|
*/
|
|
protected $method = null;
|
|
|
|
/**
|
|
* The current module
|
|
*
|
|
* @var string
|
|
*/
|
|
public $module = '';
|
|
|
|
/**
|
|
* The current controller directory
|
|
*
|
|
* @var string
|
|
*/
|
|
public $directory = '';
|
|
|
|
/**
|
|
* The request's controller
|
|
*
|
|
* @var string
|
|
*/
|
|
public $controller = '';
|
|
|
|
/**
|
|
* The request's controller action
|
|
*
|
|
* @var string
|
|
*/
|
|
public $action = '';
|
|
|
|
/**
|
|
* The request's method params
|
|
*
|
|
* @var array
|
|
*/
|
|
public $method_params = array();
|
|
|
|
/**
|
|
* The request's named params
|
|
*
|
|
* @var array
|
|
*/
|
|
public $named_params = array();
|
|
|
|
/**
|
|
* Controller instance once instantiated
|
|
*
|
|
* @var Controller
|
|
*/
|
|
public $controller_instance;
|
|
|
|
/**
|
|
* Search paths for the current active request
|
|
*
|
|
* @var array
|
|
*/
|
|
public $paths = array();
|
|
|
|
/**
|
|
* Request that created this one
|
|
*
|
|
* @var Request
|
|
*/
|
|
protected $parent = null;
|
|
|
|
/**
|
|
* Requests created by this request
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $children = array();
|
|
|
|
/**
|
|
* Creates the new Request object by getting a new URI object, then parsing
|
|
* the uri with the Route class.
|
|
*
|
|
* Usage:
|
|
*
|
|
* $request = new Request('foo/bar');
|
|
*
|
|
* @param string $uri the uri string
|
|
* @param bool $route whether or not to route the URI
|
|
* @param string $method request method
|
|
* @throws \FuelException
|
|
*/
|
|
public function __construct($uri, $route = true, $method = null)
|
|
{
|
|
$this->uri = new \Uri($uri);
|
|
$this->method = $method ?: \Input::method();
|
|
|
|
logger(\Fuel::L_INFO, 'Creating a new '.(static::$main==null ? 'main' : 'HMVC').' Request with URI = "'.$this->uri->get().'"', __METHOD__);
|
|
|
|
// check if a module was requested
|
|
if (count($this->uri->get_segments()) and $module_path = \Module::exists($this->uri->get_segment(1)))
|
|
{
|
|
// check if the module has routes
|
|
if (is_file($module_path .= 'config/routes.php'))
|
|
{
|
|
$module = $this->uri->get_segment(1);
|
|
|
|
// load and add the module routes
|
|
$module_routes = \Fuel::load($module_path);
|
|
|
|
$reserve_routes = array(
|
|
'_root_' => $module,
|
|
'_403_' => '_403_',
|
|
'_404_' => '_404_',
|
|
'_500_' => '_500_',
|
|
$module => $module,
|
|
);
|
|
|
|
$prepped_routes = array();
|
|
foreach($module_routes as $name => $_route)
|
|
{
|
|
if (isset($reserve_routes[$name]))
|
|
{
|
|
$name = $reserve_routes[$name];
|
|
}
|
|
elseif (strpos($name, $module.'/') !== 0)
|
|
{
|
|
$name = $module.'/'.$name;
|
|
}
|
|
|
|
$prepped_routes[$name] = $_route;
|
|
};
|
|
|
|
// update the loaded list of routes
|
|
\Router::add($prepped_routes, null, true);
|
|
}
|
|
}
|
|
|
|
$this->route = \Router::process($this, $route);
|
|
|
|
if ( ! $this->route)
|
|
{
|
|
return;
|
|
}
|
|
|
|
$this->module = $this->route->module;
|
|
$this->controller = $this->route->controller;
|
|
$this->action = $this->route->action;
|
|
$this->method_params = $this->route->method_params;
|
|
$this->named_params = $this->route->named_params;
|
|
|
|
if ($this->route->module !== null)
|
|
{
|
|
$this->add_path(\Module::exists($this->module));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This executes the request and sets the output to be used later.
|
|
*
|
|
* Usage:
|
|
*
|
|
* $request = Request::forge('hello/world')->execute();
|
|
*
|
|
* @param array|null $method_params An array of parameters to pass to the method being executed
|
|
* @return Request This request object
|
|
* @throws \Exception
|
|
* @throws \FuelException
|
|
* @throws \HttpNotFoundException
|
|
*/
|
|
public function execute($method_params = null)
|
|
{
|
|
// fire any request started events
|
|
\Event::instance()->has_events('request_started') and \Event::instance()->trigger('request_started', '', 'none');
|
|
|
|
if (\Fuel::$profiling)
|
|
{
|
|
\Profiler::mark(__METHOD__.': Start of '.$this->uri->get());
|
|
}
|
|
|
|
logger(\Fuel::L_INFO, 'Called', __METHOD__);
|
|
|
|
// Make the current request active
|
|
static::$active = $this;
|
|
|
|
// First request called is also the main request
|
|
if ( ! static::$main)
|
|
{
|
|
logger(\Fuel::L_INFO, 'Setting main Request', __METHOD__);
|
|
static::$main = $this;
|
|
}
|
|
|
|
if ( ! $this->route)
|
|
{
|
|
static::reset_request();
|
|
throw new \HttpNotFoundException();
|
|
}
|
|
|
|
// save the current language so we can restore it after the call
|
|
$current_language = \Config::get('language', 'en');
|
|
|
|
try
|
|
{
|
|
if ($this->route->callable !== null)
|
|
{
|
|
$response = call_fuel_func_array($this->route->callable, array($this));
|
|
|
|
if ( ! $response instanceof Response)
|
|
{
|
|
$response = new \Response($response);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$method_prefix = $this->method.'_';
|
|
$class = $this->controller;
|
|
|
|
// Allow override of method params from execute
|
|
if (is_array($method_params))
|
|
{
|
|
$this->method_params = array_merge($this->method_params, $method_params);
|
|
}
|
|
|
|
// If the class doesn't exist then 404
|
|
if ( ! class_exists($class))
|
|
{
|
|
throw new \HttpNotFoundException();
|
|
}
|
|
|
|
// Load the controller using reflection
|
|
$class = new \ReflectionClass($class);
|
|
|
|
if ($class->isAbstract())
|
|
{
|
|
throw new \HttpNotFoundException();
|
|
}
|
|
|
|
// Create a new instance of the controller
|
|
$this->controller_instance = $class->newInstance($this);
|
|
|
|
$this->action = $this->action ?: ($class->hasProperty('default_action') ? $class->getProperty('default_action')->getValue($this->controller_instance) : 'index');
|
|
$method = $method_prefix.$this->action;
|
|
|
|
// Allow to do in controller routing if method router(action, params) exists
|
|
if ($class->hasMethod('router'))
|
|
{
|
|
$method = 'router';
|
|
$this->method_params = array($this->action, $this->method_params);
|
|
}
|
|
|
|
if ( ! $class->hasMethod($method))
|
|
{
|
|
// If they call user, go to $this->post_user();
|
|
$method = strtolower(\Input::method()) . '_' . $this->action;
|
|
|
|
// Fall back to action_ if no HTTP request method based method exists
|
|
if ( ! $class->hasMethod($method))
|
|
{
|
|
$method = 'action_'.$this->action;
|
|
}
|
|
}
|
|
|
|
if ($class->hasMethod($method))
|
|
{
|
|
$action = $class->getMethod($method);
|
|
|
|
if ( ! $action->isPublic())
|
|
{
|
|
throw new \HttpNotFoundException();
|
|
}
|
|
|
|
if (count($this->method_params) < $action->getNumberOfRequiredParameters())
|
|
{
|
|
throw new \HttpNotFoundException();
|
|
}
|
|
|
|
// fire any controller started events
|
|
\Event::instance()->has_events('controller_started') and \Event::instance()->trigger('controller_started', '', 'none');
|
|
|
|
$class->hasMethod('before') and $class->getMethod('before')->invoke($this->controller_instance);
|
|
|
|
$response = $action->invokeArgs($this->controller_instance, $this->method_params);
|
|
|
|
$class->hasMethod('after') and $response = $class->getMethod('after')->invoke($this->controller_instance, $response);
|
|
|
|
// fire any controller finished events
|
|
\Event::instance()->has_events('controller_finished') and \Event::instance()->trigger('controller_finished', '', 'none');
|
|
}
|
|
else
|
|
{
|
|
throw new \HttpNotFoundException();
|
|
}
|
|
}
|
|
|
|
// restore the language setting
|
|
\Config::set('language', $current_language);
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
static::reset_request();
|
|
|
|
// restore the language setting
|
|
\Config::set('language', $current_language);
|
|
|
|
throw $e;
|
|
}
|
|
|
|
// Get the controller's output
|
|
if ($response instanceof Response)
|
|
{
|
|
$this->response = $response;
|
|
}
|
|
else
|
|
{
|
|
throw new \FuelException(get_class($this->controller_instance).'::'.$method.'() or the controller after() method must return a Response object.');
|
|
}
|
|
|
|
// fire any request finished events
|
|
\Event::instance()->has_events('request_finished') and \Event::instance()->trigger('request_finished', '', 'none');
|
|
|
|
if (\Fuel::$profiling)
|
|
{
|
|
\Profiler::mark(__METHOD__.': End of '.$this->uri->get());
|
|
}
|
|
|
|
static::reset_request();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Sets the request method.
|
|
*
|
|
* @param string $method request method
|
|
* @return object current instance
|
|
*/
|
|
public function set_method($method)
|
|
{
|
|
$this->method = strtoupper($method);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns the request method.
|
|
*
|
|
* @return string request method
|
|
*/
|
|
public function get_method()
|
|
{
|
|
return $this->method;
|
|
}
|
|
|
|
/**
|
|
* Gets this Request's Response object;
|
|
*
|
|
* Usage:
|
|
*
|
|
* $response = Request::forge('foo/bar')->execute()->response();
|
|
*
|
|
* @return Response This Request's Response object
|
|
*/
|
|
public function response()
|
|
{
|
|
return $this->response;
|
|
}
|
|
|
|
/**
|
|
* Returns the Request that created this one
|
|
*
|
|
* @return Request|null
|
|
*/
|
|
public function parent()
|
|
{
|
|
return $this->parent;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of Requests created by this one
|
|
*
|
|
* @return array
|
|
*/
|
|
public function children()
|
|
{
|
|
return $this->children;
|
|
}
|
|
|
|
/**
|
|
* Add to paths which are used by Finder::search()
|
|
*
|
|
* @param string the new path
|
|
* @param bool whether to add to the front or the back of the array
|
|
* @return void
|
|
*/
|
|
public function add_path($path, $prefix = false)
|
|
{
|
|
if ($prefix)
|
|
{
|
|
// prefix the path to the paths array
|
|
array_unshift($this->paths, $path);
|
|
}
|
|
else
|
|
{
|
|
// add the new path
|
|
$this->paths[] = $path;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the array of currently loaded search paths.
|
|
*
|
|
* @return array the array of paths
|
|
*/
|
|
public function get_paths()
|
|
{
|
|
return $this->paths;
|
|
}
|
|
|
|
/**
|
|
* Gets a specific named parameter
|
|
*
|
|
* @param string $param Name of the parameter
|
|
* @param mixed $default Default value
|
|
* @return mixed
|
|
*/
|
|
public function param($param, $default = null)
|
|
{
|
|
if ( ! isset($this->named_params[$param]))
|
|
{
|
|
return \Fuel::value($default);
|
|
}
|
|
|
|
return $this->named_params[$param];
|
|
}
|
|
|
|
/**
|
|
* Gets all of the named parameters
|
|
*
|
|
* @return array
|
|
*/
|
|
public function params()
|
|
{
|
|
return $this->named_params;
|
|
}
|
|
|
|
/**
|
|
* PHP magic function returns the Output of the request.
|
|
*
|
|
* Usage:
|
|
*
|
|
* $request = Request::forge('hello/world')->execute();
|
|
* echo $request;
|
|
*
|
|
* @return string the response
|
|
*/
|
|
public function __toString()
|
|
{
|
|
return (string) $this->response;
|
|
}
|
|
}
|