Commit: 80d76020c7ff106416cc60e77591b6beaaea1f84

Author: Nate Abele | Date: 2009-07-03 18:23:06 -0400
Initial code & docs commit.
diff --git a/.gitignore b/.gitignore index e69de29..496ee2c 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/exceptions/NotFoundException.php b/exceptions/NotFoundException.php new file mode 100644 index 0000000..3e43237 --- /dev/null +++ b/exceptions/NotFoundException.php @@ -0,0 +1,8 @@ +<?php + +namespace slice\exceptions; + +class NotFoundException extends \Exception { +} + +?> \ No newline at end of file diff --git a/extensions/http/Dispatcher.php b/extensions/http/Dispatcher.php new file mode 100644 index 0000000..474c3f4 --- /dev/null +++ b/extensions/http/Dispatcher.php @@ -0,0 +1,34 @@ +<?php + +namespace slice\extensions\http; + +class Dispatcher extends \cake\http\Dispatcher { + + protected static $_classes = array( + 'request' => '\slice\extensions\http\Request', + 'router' => '\slice\extensions\http\Router' + ); + + public static function run($request, $options = array(), $methods = array()) { + if (is_array($request) && is_callable(current($request))) { + $methods = $request; + $options['methods'] = $methods; + $request = null; + } + $router = static::$_classes['router']; + $router::connect(array_keys($methods)); + $result = parent::run($request, $options); + + var_dump($result); + static::_stop(); + } + + protected static function _callable($request, $params, $options) { + if (!isset($params['route']) || !isset($options['methods'])) { + return null; + } + return $options['methods'][$params['route']]; + } +} + +?> \ No newline at end of file diff --git a/extensions/http/Request.php b/extensions/http/Request.php new file mode 100644 index 0000000..1118a68 --- /dev/null +++ b/extensions/http/Request.php @@ -0,0 +1,12 @@ +<?php + +namespace slice\extensions\http; + +class Request extends \cake\http\Request { + + public function __get($key) { + return isset($this->params[$key]) ? $this->params[$key] : $this->env($key); + } +} + +?> \ No newline at end of file diff --git a/extensions/http/Router.php b/extensions/http/Router.php new file mode 100644 index 0000000..7afbc89 --- /dev/null +++ b/extensions/http/Router.php @@ -0,0 +1,33 @@ +<?php + +namespace slice\extensions\http; + +class Router extends \cake\http\Router { + + protected static $_configuration = array(); + + public static function connect($routes) { + static::$_configuration = $routes; + } + + public static function parse($request) { + $requestMethod = strtolower($request->env('REQUEST_METHOD')); + $class = static::$_classes['route']; + + foreach (static::$_configuration as $route) { + list($method, $template) = explode(' ', $route, 2); + + if ($method != $requestMethod) { + continue; + } + $routeObject = new $class(compact('template')); + $routeObject->compile(); + + if ($match = $routeObject->parse($request)) { + return compact('route') + $match; + } + } + } +} + +?> \ No newline at end of file diff --git a/readme b/readme new file mode 100644 index 0000000..4d01e71 --- /dev/null +++ b/readme @@ -0,0 +1,46 @@ +## Slice: The Lightweight Request Dispatch Framework for CakePHP + +Slice is a plugin which allows you to implement micro-applications or application services using the CakePHP framework. Slice is ideally suited to serving small requests, such as APIs or Ajax queries, where speed is of the essence. + +To use Slice in your application, simply install it in your `plugins` directory and include it by adding the following to `config/bootstrap.php` or `webroot/index.php`: + +{{{ +\cake\core\Libraries::add('plugin', 'slice'); +}}} + +You can then implement Slice services by calling the `run()` method of `slice\extensions\http\Dispatcher`, and passing it an array where the keys are Slice-formatted routes and the values are closures which define how requests matching the corresponding route should be handled. + +{{{ + +use \Exception; +use \app\models\Post; +use \slice\exceptions\NotFoundException; +use \slice\extensions\http\Dispatcher; + +echo Dispatcher::run(array( + 'get /posts/{:id:\d+}.json' => function($request) { + try { + return array( + 'status' => 200, + 'type' => 'application/json', + 'content' => Post::find($request->id)->to('json') + ); + } catch (Exception $e) { + throw new NotFoundException(); + } + } +)); + +}}} + +### Routing + +The syntax for declaring routes in Slice is similar to that of Cake 3.0 standard routes, except that Slice routes are prefixed with an HTTP request method name, followed by a space. Routes can then include standard parameters, with optional regular expression match patterns, as in the example. + +### Handling requests + +Closures used to handle requests in Slice take a single parameter, an instance of the `Request` object, which encapsulates the request details. Slice extends the default CakePHP `Request` object so that route parameters are accessible as properties (i.e. `$request->id`), as seen in the example. + +In order to successfully handle requests, closures must _either_ return an array containing (at a minimum) `'status'`, `'type'`, and `'content'` keys, and optionally, a `'headers'` key containing an array with additional headers, _or_ an instance of `cake\http\Response` containing a fully-formed response. + +Alternatively, closures can throw exceptions in case of error, or ignore the request, simply by returning null. If a request is ignored, it simply "falls through", out of the scope of Slice. This is useful if you are declaring a Slice service inside of `webroot/index.php`, and wish for requests ignored by Slice to be handled by your application. \ No newline at end of file