├── .gitignore ├── .travis.yml ├── LICENSE ├── README.markdown ├── composer.json ├── phpunit.xml.dist ├── src └── SlimController │ ├── Slim.php │ └── SlimController.php └── tests ├── SlimController └── Tests │ ├── Fixtures │ ├── Controller │ │ └── TestController.php │ └── templates │ │ └── rendertest.php │ ├── Integration │ └── CanCreateApplicationTest.php │ ├── Old │ ├── ControllerTest.php │ ├── ParamsTest.php │ ├── RenderTest.php │ └── RoutingTest.php │ ├── SlimControllerTest.php │ ├── SlimTest.php │ └── TestCase.php └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor/ 3 | composer.lock -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | before_script: 9 | - curl -s http://getcomposer.org/installer | php 10 | - php composer.phar install --dev 11 | 12 | script: phpunit -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT LICENSE 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | The above copyright notice and this permission notice shall be 11 | included in all copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 13 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 14 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 17 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 18 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # SlimController 2 | 3 | SlimController is an extension for [the Slim Framework](http://www.slimframework.com/) providing the C of MVC. 4 | 5 | With Slim alone, you can create great applications very, very quickly. Sometimes things get out of hand an you just need a bit more structure - or at least I do. That's what SlimController is for. 6 | 7 | [![Latest Stable Version](https://poser.pugx.org/slimcontroller/slimcontroller/v/stable.png)](https://packagist.org/packages/slimcontroller/slimcontroller) 8 | [![Total Downloads](https://poser.pugx.org/slimcontroller/slimcontroller/downloads.png)](https://packagist.org/packages/slimcontroller/slimcontroller) 9 | 10 | [![Build Status](https://travis-ci.org/fortrabbit/slimcontroller.png?branch=master)](https://travis-ci.org/fortrabbit/slimcontroller) 11 | 12 | # Install via composer 13 | 14 | Create a `composer.json` file 15 | 16 | { 17 | "require": { 18 | "slimcontroller/slimcontroller": "0.4.3" 19 | }, 20 | "autoload": { 21 | "psr-0": { 22 | "MyApp": "src/" 23 | } 24 | } 25 | } 26 | 27 | Run installation 28 | 29 | composer.phar install --dev 30 | 31 | # Mini HowTo 32 | 33 | If you know how [Slim works](http://docs.slimframework.com/), using SlimController shouldn't be a big deal. 34 | 35 | ## Example Structure 36 | 37 | Setup a structure for your controller and templates (just a suggestion, do as you like): 38 | 39 | mkdir -p src/MyApp/Controller templates/home 40 | 41 | ## Controller 42 | 43 | Create your first controller in `src/MyApp/Controller/Home.php` 44 | 45 | render('home/index', array( 55 | 'someVar' => date('c') 56 | )); 57 | } 58 | 59 | public function helloAction($name) 60 | { 61 | $this->render('home/hello', array( 62 | 'name' => $name 63 | )); 64 | } 65 | } 66 | 67 | ## Templates 68 | 69 | Here are the two corresponding demo templates: 70 | 71 | `templates/home/index.php` 72 | 73 | This is the SlimController extension @ 74 | 75 | `templates/home/hello.php` 76 | 77 | Hello 78 | 79 | ## Boostrap index.php 80 | 81 | Minimal bootstrap file for this example 82 | 83 | APP_PATH . '/templates', 94 | 'controller.class_prefix' => '\\MyApp\\Controller', 95 | 'controller.method_suffix' => 'Action', 96 | 'controller.template_suffix' => 'php', 97 | )); 98 | 99 | $app->addRoutes(array( 100 | '/' => 'Home:index', 101 | '/hello/:name' => 'Home:hello', 102 | )); 103 | 104 | $app->run(); 105 | 106 | ## Run 107 | 108 | php -S localhost:8080 109 | 110 | 111 | # Controller 112 | 113 | ## Configuration 114 | 115 | ### controller.class_prefix 116 | 117 | Optional class prefix for controller classes. Will be prepended to routes. 118 | 119 | Using `\\MyApp\\Controller` as prefix with given routes: 120 | 121 | $app->addRoutes(array( 122 | '/' => 'Home:index', 123 | '/hello/:name' => 'Home:hello', 124 | )); 125 | 126 | Translates to 127 | 128 | $app->addRoutes(array( 129 | '/' => '\\MyApp\\Controller\\Home:index', 130 | '/hello/:name' => '\\MyApp\\Controller\\Home:hello', 131 | )); 132 | 133 | ### controller.class_suffix 134 | 135 | Optional class suffix for controller classes. Will be appended to routes. 136 | 137 | Using `Controller` as suffix with given routes: 138 | 139 | $app->addRoutes(array( 140 | '/' => 'Home:index', 141 | '/hello/:name' => 'Home:hello', 142 | )); 143 | 144 | Translates to 145 | 146 | $app->addRoutes(array( 147 | '/' => 'HomeController:index', 148 | '/hello/:name' => 'HomeController:hello', 149 | )); 150 | 151 | ### controller.method_suffix 152 | 153 | Optional method suffix. Appended to routes. 154 | 155 | Using `Action` as suffix with given routes: 156 | 157 | $app->addRoutes(array( 158 | '/' => 'Home:index', 159 | '/hello/:name' => 'Home:hello', 160 | )); 161 | 162 | Translates to 163 | 164 | $app->addRoutes(array( 165 | '/' => 'Home:indexAction', 166 | '/hello/:name' => 'Home:helloAction', 167 | )); 168 | 169 | ### controller.template_suffix 170 | 171 | Defaults to `twig`. Will be appended to template name given in `render()` method. 172 | 173 | ## Extended Examples 174 | 175 | ### Routes 176 | 177 | // how to integrate the Slim middleware 178 | $app->addRoutes(array( 179 | '/' => array('Home:index', function() { 180 | error_log("MIDDLEWARE FOR SINGLE ROUTE"); 181 | }, 182 | function() { 183 | error_log("ADDITIONAL MIDDLEWARE FOR SINGLE ROUTE"); 184 | } 185 | ), 186 | '/hello/:name' => array('post' => array('Home:hello', function() { 187 | error_log("THIS ROUTE IS ONLY POST"); 188 | } 189 | )) 190 | ), function() { 191 | error_log("APPENDED MIDDLEWARE FOR ALL ROUTES"); 192 | }); 193 | 194 | ### Controller 195 | 196 | app->response()->status(404); 211 | 212 | 213 | /** 214 | * Params 215 | */ 216 | 217 | // reads "?data[foo]=some+value" 218 | $foo = $this->param('foo'); 219 | 220 | // reads "data[bar][name]=some+value" only if POST! 221 | $bar = $this->param('bar.name', 'post'); 222 | 223 | // all params of bar ("object attributes") 224 | // "?data[bar][name]=me&data[bar][mood]=happy" only if POST! 225 | $bar = $this->param('bar'); 226 | //error_log($bar['name']. ' is '. $bar['mood']); 227 | 228 | // reads multiple params in array 229 | $params = $this->params(array('foo', 'bar.name1', 'bar.name1')); 230 | //error_log($params['bar.name1']); 231 | 232 | // reads multiple params only if they are POST 233 | $params = $this->params(array('foo', 'bar.name1', 'bar.name1'), 'post'); 234 | 235 | // reads multiple params only if they are POST and all are given! 236 | $params = $this->params(array('foo', 'bar.name1', 'bar.name1'), 'post', true); 237 | if (!$params) { 238 | error_log("Not all params given.. maybe some. Don't care"); 239 | } 240 | 241 | // reads multiple params only if they are POST and replaces non given with defaults! 242 | $params = $this->params(array('foo', 'bar.name1', 'bar.name1'), 'post', array( 243 | 'foo' => 'Some Default' 244 | )); 245 | 246 | 247 | /** 248 | * Redirect shortcut 249 | */ 250 | 251 | if (false) { 252 | $this->redirect('/somewhere'); 253 | } 254 | 255 | 256 | /** 257 | * Rendering 258 | */ 259 | 260 | $this->render('folder/file', array( 261 | 'foo' => 'bar' 262 | )); 263 | 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slimcontroller/slimcontroller", 3 | "version": "0.4.3", 4 | "type": "library", 5 | "description": "Controller extensions for the Slim Framework", 6 | "keywords": ["microframework", "controller"], 7 | "homepage": "http://github.com/fortrabbit/slimcontroller", 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Ulrich Kautz", 12 | "email": "uk@fortrabbit.de", 13 | "homepage": "http://fortrabbit.com/" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.3.0", 18 | "slim/slim": "2.*" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "4.3.5", 22 | "mockery/mockery": "0.8.*" 23 | }, 24 | "autoload": { 25 | "psr-0": { 26 | "SlimController": "src/" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/SlimController/Tests 16 | ./tests/SlimController/Tests/Old/ 17 | 18 | 19 | 20 | 21 | src 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/SlimController/Slim.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright 2012 Ulrich Kautz 8 | * @version 0.1.2 9 | * @package SlimController 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace SlimController; 16 | 17 | /** 18 | * Extended Slim base 19 | */ 20 | class Slim extends \Slim\Slim 21 | { 22 | /** 23 | * @var array 24 | */ 25 | protected static $ALLOWED_HTTP_METHODS = array('ANY', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'); 26 | 27 | /** 28 | * @var array 29 | */ 30 | protected $routeNames = array(); 31 | 32 | /** 33 | * Add multiple controller based routes 34 | * 35 | * Simple Format 36 | * 37 | * $app->addRoutes(array( 38 | * '/some/path' => 'className:methodName' 39 | * )); 40 | * 41 | * 42 | * With explicit HTTP method 43 | * 44 | * $app->addRoutes(array( 45 | * '/some/path' => array('get' => 'className:methodName') 46 | * )); 47 | * 48 | * 49 | * With local middleware 50 | * 51 | * $app->addRoutes(array( 52 | * '/some/path' => array('get' => 'className:methodName', function() {}) 53 | * '/other/path' => array('className:methodName', function() {}) 54 | * )); 55 | * 56 | * 57 | * With global middleware 58 | * 59 | * $app->addRoutes(array( 60 | * '/some/path' => 'className:methodName', 61 | * ), function() {}); 62 | * 63 | * 64 | * @param array $routes The route definitions 65 | * @param array $globalMiddlewares 66 | * @throws \InvalidArgumentException 67 | * @internal param $callable ,... $middlewares Optional callable used for all routes as middleware 68 | * 69 | * @return $this 70 | */ 71 | public function addRoutes(array $routes, $globalMiddlewares = array()) 72 | { 73 | if (!is_array($globalMiddlewares)) { 74 | if (func_num_args() > 2) { 75 | $args = func_get_args(); 76 | $globalMiddlewares = array_slice($args, 1); 77 | } else { 78 | $globalMiddlewares = array($globalMiddlewares); 79 | } 80 | } 81 | 82 | foreach ($routes as $path => $routeArgs) { 83 | // create array for simple request 84 | $routeArgs = (is_array($routeArgs)) ? $routeArgs : array('any' => $routeArgs); 85 | 86 | if (array_keys($routeArgs) === range(0, count($routeArgs) - 1)) { 87 | // route args is a sequential array not associative 88 | $routeArgs = array('any' => array($routeArgs[0], 89 | isset($routeArgs[1]) && is_array($routeArgs[1]) ? $routeArgs[1] : array_slice($routeArgs, 1)) 90 | ); 91 | } 92 | 93 | foreach ($routeArgs as $httpMethod => $classArgs) { 94 | // assign vars if middleware callback exists 95 | if (is_array($classArgs)) { 96 | $classRoute = $classArgs[0]; 97 | $localMiddlewares = is_array($classArgs[1]) ? $classArgs[1] : array_slice($classArgs, 1); 98 | } else { 99 | $classRoute = $classArgs; 100 | $localMiddlewares = array(); 101 | } 102 | 103 | // specific HTTP method 104 | $httpMethod = strtoupper($httpMethod); 105 | if (!in_array($httpMethod, static::$ALLOWED_HTTP_METHODS)) { 106 | throw new \InvalidArgumentException("Http method '$httpMethod' is not supported."); 107 | } 108 | 109 | $routeMiddlewares = array_merge($localMiddlewares, $globalMiddlewares); 110 | $route = $this->addControllerRoute($path, $classRoute, $routeMiddlewares); 111 | 112 | if (!isset($this->routeNames[$classRoute])) { 113 | $route->name($classRoute); 114 | $this->routeNames[$classRoute] = 1; 115 | } 116 | 117 | if ('any' === $httpMethod) { 118 | call_user_func_array(array($route, 'via'), static::$ALLOWED_HTTP_METHODS); 119 | } else { 120 | $route->via($httpMethod); 121 | } 122 | } 123 | } 124 | 125 | return $this; 126 | } 127 | 128 | /** 129 | * Add a new controller route 130 | * 131 | * 132 | * $app->addControllerRoute("/the/path", "className:methodName", array(function () { doSome(); })) 133 | * ->via('GET')->condition(..); 134 | * 135 | * $app->addControllerRoute("/the/path", "className:methodName") 136 | * ->via('GET')->condition(..); 137 | * 138 | * 139 | * @param string $path 140 | * @param string $route 141 | * @param callable[] $middleware,... 142 | * 143 | * @return \Slim\Route 144 | */ 145 | public function addControllerRoute($path, $route, array $middleware = array()) 146 | { 147 | $callback = $this->buildCallbackFromControllerRoute($route); 148 | 149 | array_unshift($middleware, $path); 150 | array_push($middleware, $callback); 151 | 152 | $route = call_user_func_array(array($this, 'map'), $middleware); 153 | 154 | return $route; 155 | } 156 | 157 | /** 158 | * Builds closure callback from controller route 159 | * 160 | * @param $route 161 | * 162 | * @return \Closure 163 | */ 164 | protected function buildCallbackFromControllerRoute($route) 165 | { 166 | list($controller, $methodName) = $this->determineClassAndMethod($route); 167 | $app = & $this; 168 | $callable = function () use ($app, $controller, $methodName) { 169 | // Get action arguments 170 | $args = func_get_args(); 171 | // Try to fetch the instance from Slim's container, otherwise lazy-instantiate it 172 | $instance = $app->container->has($controller) ? $app->container->get($controller) : new $controller($app); 173 | 174 | return call_user_func_array(array($instance, $methodName), $args); 175 | }; 176 | 177 | return $callable; 178 | } 179 | 180 | /** 181 | * @param string $classMethod 182 | * 183 | * @return array 184 | * @throws \InvalidArgumentException 185 | */ 186 | protected function determineClassAndMethod($classMethod) 187 | { 188 | // determine class prefix (eg "\Vendor\Bundle\Controller") and suffix (eg "Controller") 189 | $classNamePrefix = $this->config('controller.class_prefix'); 190 | if ($classNamePrefix && substr($classNamePrefix, -strlen($classNamePrefix) !== '\\')) { 191 | $classNamePrefix .= '\\'; 192 | } 193 | $classNameSuffix = $this->config('controller.class_suffix') ? : ''; 194 | 195 | // determine method suffix or default to "Action" 196 | $methodNameSuffix = $this->config('controller.method_suffix'); 197 | if (is_null($methodNameSuffix)) { 198 | $methodNameSuffix = 'Action'; 199 | } 200 | $realClassMethod = $classMethod; 201 | if (strpos($realClassMethod, '\\') !== 0) { 202 | $realClassMethod = $classNamePrefix . $classMethod; 203 | } 204 | 205 | // having : 206 | if (preg_match('/^([a-zA-Z0-9\\\\_]+):([a-zA-Z0-9_]+)$/', $realClassMethod, $match)) { 207 | $className = $match[1] . $classNameSuffix; 208 | $methodName = $match[2] . $methodNameSuffix; 209 | } // malformed 210 | else { 211 | throw new \InvalidArgumentException( 212 | "Malformed class action for '$classMethod'. Use 'className:methodName' format." 213 | ); 214 | } 215 | 216 | return array($className, $methodName); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/SlimController/SlimController.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright 2012 Ulrich Kautz 8 | * @version 0.1.2 9 | * @package SlimController 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace SlimController; 16 | 17 | /** 18 | * Implements a basic controller functionallity. 19 | * It should not be instanciated directly but extended from. 20 | */ 21 | abstract class SlimController 22 | { 23 | /** 24 | * @const string 25 | */ 26 | const VERSION = '0.1.4'; 27 | 28 | /** 29 | * @var Slim 30 | */ 31 | protected $app; 32 | 33 | /** 34 | * @var bool Whether cleanup params or not 35 | */ 36 | protected $paramCleanup = false; 37 | 38 | /** 39 | * @var string Prefix for params 40 | */ 41 | private $paramPrefix = 'data.'; 42 | 43 | /** 44 | * @var array Stash of GET & POST params 45 | */ 46 | private $paramsParams = null; 47 | 48 | /** 49 | * @var array Stash of GET params 50 | */ 51 | private $paramsGet = null; 52 | 53 | /** 54 | * @var array Stash of POST params 55 | */ 56 | private $paramsPost = null; 57 | 58 | /** 59 | * Suffix was never specified and defaults to empty string 60 | * 61 | * @var string 62 | */ 63 | protected $renderTemplateSuffix = 'twig'; 64 | 65 | /** 66 | * Constructor for TodoQueue\Controller\Login 67 | * 68 | * @param \Slim\Slim $app Ref to slim app 69 | */ 70 | public function __construct(\Slim\Slim &$app) 71 | { 72 | $this->app = $app; 73 | if ($renderTemplateSuffix = $app->config('controller.template_suffix')) { 74 | $this->renderTemplateSuffix = $renderTemplateSuffix; 75 | } 76 | if (!is_null($paramPrefix = $app->config('controller.param_prefix'))) { 77 | $this->paramPrefix = $paramPrefix; 78 | $prefixLength = strlen($this->paramPrefix); 79 | if ($prefixLength > 0 && substr($this->paramPrefix, -$prefixLength) !== '.') { 80 | $this->paramPrefix .= '.'; 81 | } 82 | } 83 | if ($app->config('controller.cleanup_params')) { 84 | $this->paramCleanup = true; 85 | } 86 | } 87 | 88 | /** 89 | * Renders output with given template 90 | * 91 | * @param string $template Name of the template to be rendererd 92 | * @param array $args Args for view 93 | */ 94 | protected function render($template, $args = array()) 95 | { 96 | if (!is_null($this->renderTemplateSuffix) 97 | && !preg_match('/\.' . $this->renderTemplateSuffix . '$/', $template) 98 | ) { 99 | $template .= '.' . $this->renderTemplateSuffix; 100 | } 101 | $this->app->render($template, $args); 102 | } 103 | 104 | /** 105 | * Performs redirect 106 | * 107 | * @param string $path 108 | */ 109 | protected function redirect($path) 110 | { 111 | $this->app->redirect($path); 112 | } 113 | 114 | /** 115 | * Slim's request object 116 | * 117 | * @return \Slim\Http\Request 118 | */ 119 | protected function request() 120 | { 121 | return $this->app->request(); 122 | } 123 | 124 | /** 125 | * Slim's response object 126 | * 127 | * @return \Slim\Http\Response 128 | */ 129 | protected function response() 130 | { 131 | return $this->app->response(); 132 | } 133 | 134 | /** 135 | * Returns a single parameter of the "data[Object][Key]" format. 136 | * 137 | * 138 | * $paramValue = $this->param('prefix.name'); // prefix[name] -> "string value" 139 | * $paramValue = $this->param('prefix.name', 'post'); // prefix[name] -> "string value" 140 | * $paramValue = $this->param('prefix.name', 'get'); // prefix[name] -> "string value" 141 | * 142 | * 143 | * @param mixed $name Name of the parameter 144 | * @param mixed $reqMode Optional mode. Either null (all params), true | "post" 145 | * (only POST params), false | "get" (only GET params) 146 | * @param mixed $cleanup Whether use simple cleanup 147 | * 148 | * @return mixed Either array or single string or null 149 | */ 150 | protected function param($name, $reqMode = null, $cleanup = null) 151 | { 152 | $cleanup = is_null($cleanup) ? $this->paramCleanup : $cleanup; 153 | $name = $this->paramPrefix . $name; 154 | $reqMeth = $this->paramAccessorMeth($reqMode); 155 | 156 | // determine stash name 157 | $reqStashName = 'params' . ucfirst($reqMeth); 158 | if (is_null($this->$reqStashName)) { 159 | $this->$reqStashName = $this->request()->$reqMeth(); 160 | } 161 | $params = $this->$reqStashName; 162 | 163 | // split of parts and go through 164 | $parts = preg_split('/\./', $name); 165 | while (isset($params[$parts[0]])) { 166 | $params = $params[$parts[0]]; 167 | array_shift($parts); 168 | if (empty($parts)) { 169 | return $cleanup === true ? $this->cleanupParam($params) : $params; 170 | } 171 | } 172 | 173 | return null; 174 | } 175 | 176 | /** 177 | * Reads multiple params at once 178 | * 179 | * 180 | * $params = $this->params(['prefix.name', 'other.name']); // -> ["prefix.name" => "value", ..] 181 | * $params = $this->params(['prefix.name', 'other.name'], true); // -> null if not all found 182 | * $params = $this->params(['prefix.name', 'other.name'], ['other.name' => "Default Value"]); 183 | * 184 | * 185 | * @param mixed $names Name or names of parameters (GET or POST) 186 | * @param mixed $reqMode Optional mode. Either null (all params), true | "post" 187 | * (only POST params), false | "get" (only GET params) 188 | * @param mixed $defaults Either true (require ALL given or return null), array (defaults) 189 | * 190 | * @return mixed Either array or single string or null 191 | */ 192 | protected function params($names = array(), $reqMode = null, $defaults = null) 193 | { 194 | // no names given -> get them all 195 | if (!$names) { 196 | $names = $this->getAllParamNames($reqMode); 197 | } 198 | $res = array(); 199 | foreach ($names as $obj) { 200 | $name = is_array($obj) ? $obj[0] : $obj; 201 | $param = $this->param($name, $reqMode); 202 | if (!is_null($param) && (!is_array($param) || !empty($param))) { 203 | $res[$name] = $param; 204 | } // if in "need all" mode 205 | elseif ($defaults === true) { 206 | return null; 207 | } // if in default mode 208 | elseif (is_array($defaults) && isset($defaults[$name])) { 209 | $res[$name] = $defaults[$name]; 210 | } 211 | } 212 | 213 | return $res; 214 | } 215 | 216 | /** 217 | * Cleans up a single or a list of params by stripping HTML encodings 218 | * 219 | * @param string $value 220 | * 221 | * @return string 222 | */ 223 | protected function cleanupParam($value) 224 | { 225 | if (is_array($value)) { 226 | foreach ($value as $k => $v) { 227 | $clean = $this->cleanupParam($v); 228 | if (!is_null($clean)) { 229 | $value[$k] = $clean; 230 | } 231 | } 232 | 233 | return $value; 234 | } else { 235 | return preg_replace('/>/', '', preg_replace('/ ["b" => ["c" => 1]]] to ["a.b.c" => 1] 241 | * 242 | * @param array $data 243 | * 244 | * @return array 245 | */ 246 | protected function flatten(array $data) 247 | { 248 | return $this->flattenInner($data); 249 | } 250 | 251 | private function flattenInner(array $data, $prefix = '', &$flat = array()) 252 | { 253 | foreach ($data as $key => $value) { 254 | // is array -> flatten deep 255 | if (is_array($value)) { 256 | $this->flattenInner($value, $prefix . $key . '.', $flat); 257 | } // scalar -> use 258 | else { 259 | $flat[$prefix . $key] = $value; 260 | } 261 | } 262 | 263 | return $flat; 264 | } 265 | 266 | private function paramAccessorMeth($reqMode = null) 267 | { 268 | return $reqMode === true || $reqMode === 'post' // POST 269 | ? 'post' 270 | : ($reqMode === false || $reqMode === 'get' // GET 271 | ? 'get' 272 | : 'params' // ALL 273 | ); 274 | } 275 | 276 | private function getAllParamNames($reqMode) 277 | { 278 | $reqMeth = $this->paramAccessorMeth($reqMode); 279 | $params = $this->request()->$reqMeth(); 280 | $namesPre = $this->flatten($params); 281 | $names = array_keys($namesPre); 282 | if ($prefix = $this->paramPrefix) { 283 | $prefixLen = strlen($prefix); 284 | $names = array_map(function ($key) use ($prefixLen) { 285 | return substr($key, $prefixLen); 286 | }, array_filter($names, function ($in) use ($prefix) { 287 | return strpos($in, $prefix) === 0; 288 | })); 289 | } 290 | 291 | return $names; 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/Fixtures/Controller/TestController.php: -------------------------------------------------------------------------------- 1 | param('Some.param'); 23 | } 24 | 25 | public function paramSingleArrayAction() 26 | { 27 | $obj = $this->param('Some'); 28 | echo "Param is " . $obj['attrib1'] . $obj['attrib2'] . $obj['attrib3']; 29 | } 30 | 31 | public function paramMultiAction() 32 | { 33 | $params = $this->params(array('Some.param', 'Other.param', 'Other.missing')); 34 | echo json_encode($params); 35 | } 36 | 37 | public function paramMultiMissingReqAction() 38 | { 39 | $params = $this->params(array('Some.param', 'Other.param'), 'get', true); 40 | echo json_encode($params); 41 | } 42 | 43 | public function paramMultiDefaultAction() 44 | { 45 | $params = $this->params(array('Some.param', 'Other.param', 'Other.bla'), 'get', array('Other.bla' => 'great')); 46 | echo json_encode($params); 47 | } 48 | 49 | public function paramGetAllAction() 50 | { 51 | $params = $this->params(); 52 | echo json_encode($params); 53 | } 54 | 55 | public function paramCleanupAction() 56 | { 57 | $messedUp = array('foo', 'Notgood'); 58 | echo json_encode($this->cleanupParam($messedUp)); 59 | } 60 | 61 | public function renderAction() 62 | { 63 | $this->render('rendertest', array('foo' => 'orotound', 'bar' => 'grandios')); 64 | } 65 | 66 | public function redirectAction() 67 | { 68 | $this->redirect('/here'); 69 | } 70 | 71 | public function notSuffixedMethod() 72 | { 73 | echo "Yes, I was called"; 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /tests/SlimController/Tests/Fixtures/templates/rendertest.php: -------------------------------------------------------------------------------- 1 | This is and -------------------------------------------------------------------------------- /tests/SlimController/Tests/Integration/CanCreateApplicationTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); // if we got this far then creating the application worked 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/Old/ControllerTest.php: -------------------------------------------------------------------------------- 1 | expectOutputString('What is up?'); 11 | $this->setUrl('/'); 12 | $this->app->addRoutes(array( 13 | '/' => 'Test:index', 14 | )); 15 | 16 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 17 | //$this->app->router()->dispatch($route); 18 | $route->dispatch(); 19 | } 20 | 21 | public function testControllerExtended() 22 | { 23 | $this->expectOutputString('What is up YOU?'); 24 | $this->setUrl('/hello/YOU'); 25 | $this->app->addRoutes(array( 26 | '/hello/:name' => 'Test:hello', 27 | )); 28 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 29 | //$this->app->router()->dispatch($route); 30 | $route->dispatch(); 31 | } 32 | 33 | public function testControllerAbsPath() 34 | { 35 | $this->expectOutputString('What is up YOU?'); 36 | $this->setUrl('/hello/YOU'); 37 | $this->app->addRoutes(array( 38 | '/hello/:name' => 'Test:hello', 39 | )); 40 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 41 | //$this->app->router()->dispatch($route); 42 | $route->dispatch(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/Old/ParamsTest.php: -------------------------------------------------------------------------------- 1 | expectOutputString('Param is 123'); 12 | $this->setUrl('/', 'data[Some][param]=123'); 13 | $this->app->addRoutes(array( 14 | '/' => 'Test:paramSingle', 15 | )); 16 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 17 | //$this->app->router()->dispatch($route); 18 | $route->dispatch(); 19 | } 20 | 21 | 22 | public function testParamsSingleObject() 23 | { 24 | $this->expectOutputString('Param is 123123123'); 25 | $this->setUrl('/', 'data[Some][attrib1]=123&data[Some][attrib2]=123&data[Some][attrib3]=123'); 26 | $this->app->addRoutes(array( 27 | '/' => 'Test:paramSingleObject', 28 | )); 29 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 30 | //$this->app->router()->dispatch($route); 31 | $route->dispatch(); 32 | } 33 | 34 | public function testParamsMulti() 35 | { 36 | $this->expectOutputString('All is foo bar'); 37 | $this->setUrl('/', 'data[Some][param]=foo&data[Other][param]=bar'); 38 | $this->app->addRoutes(array( 39 | '/' => 'Test:paramMulti', 40 | )); 41 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 42 | //$this->app->router()->dispatch($route); 43 | $route->dispatch(); 44 | } 45 | 46 | public function testParamsMultiMissing() 47 | { 48 | $this->expectOutputString('All is foo bar'); 49 | $this->setUrl('/', 'data[Some][param]=foo&data[Other][param]=bar'); 50 | $this->app->addRoutes(array( 51 | '/' => 'Test:paramMultiMissing', 52 | )); 53 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 54 | //$this->app->router()->dispatch($route); 55 | $route->dispatch(); 56 | } 57 | 58 | public function testParamsMultiMissingReq() 59 | { 60 | $this->expectOutputString('OK'); 61 | $this->setUrl('/', 'data[Some][param]=foo&data[Other][param]=bar'); 62 | $this->app->addRoutes(array( 63 | '/' => 'Test:paramMultiMissingReq', 64 | )); 65 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 66 | //$this->app->router()->dispatch($route); 67 | $route->dispatch(); 68 | } 69 | 70 | public function testParamsMultiDefault() 71 | { 72 | $this->expectOutputString('All is foo bar and great'); 73 | $this->setUrl('/', 'data[Some][param]=foo&data[Other][param]=bar'); 74 | $this->app->addRoutes(array( 75 | '/' => 'Test:paramMultiDefault', 76 | )); 77 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 78 | //$this->app->router()->dispatch($route); 79 | $route->dispatch(); 80 | } 81 | 82 | public function testParamsDifferentPrefix() 83 | { 84 | $this->expectOutputString('GOT OK'); 85 | $this->setUrl('/', 'data[Foo]=bar&other[Foo]=bar', array( 86 | 'controller.param_prefix' => 'other.' 87 | )); 88 | $this->app->addRoutes(array( 89 | '/' => 'Test:paramDifferentPrefix', 90 | )); 91 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 92 | //$this->app->router()->dispatch($route); 93 | $route->dispatch(); 94 | } 95 | 96 | public function testParamsNoPrefix() 97 | { 98 | $this->expectOutputString('All params: data.Foo=bar - other.Foo=bar'); 99 | $this->setUrl('/', 'data[Foo]=bar&other[Foo]=bar', array( 100 | 'controller.param_prefix' => '' 101 | )); 102 | $this->app->addRoutes(array( 103 | '/' => 'Test:paramNoPrefix', 104 | )); 105 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 106 | //$this->app->router()->dispatch($route); 107 | $route->dispatch(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/Old/RenderTest.php: -------------------------------------------------------------------------------- 1 | expectOutputString('This is orotound and grandios'); 11 | $this->setUrl('/', 'data[Some][param]=foo&data[Other][param]=bar'); 12 | $this->app->addRoutes(array( 13 | '/' => 'Test:render', 14 | )); 15 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 16 | //$this->app->router()->dispatch($route); 17 | $route->dispatch(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/Old/RoutingTest.php: -------------------------------------------------------------------------------- 1 | setUrl('/'); 11 | $this->app->addRoutes(array( 12 | '/' => 'Controller:index', 13 | )); 14 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 15 | 16 | $this->setUrl('/foo'); 17 | $this->assertEquals(0, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 18 | 19 | $this->setUrl('/other'); 20 | 21 | $this->app->addRoutes(array( 22 | '/other' => 'Controller:other', 23 | )); 24 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 25 | } 26 | 27 | public function testRoutesWithVariables() 28 | { 29 | $this->setUrl('/hello/you'); 30 | $this->app->addRoutes(array( 31 | '/hello/:name' => 'Controller:index', 32 | )); 33 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 34 | } 35 | 36 | public function testRoutesWithExtendedFormat() 37 | { 38 | $this->setUrl('/bla'); 39 | $this->app->addRoutes(array( 40 | '/bla' => array('Controller:index', 'get') 41 | )); 42 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/SlimControllerTest.php: -------------------------------------------------------------------------------- 1 | slim = m::mock('\Slim\Slim'); 22 | parent::setUp(); 23 | } 24 | 25 | public function tearDown() 26 | { 27 | $this->addToAssertionCount($this->slim->mockery_getExpectationCount()); 28 | m::close(); 29 | parent::tearDown(); 30 | } 31 | 32 | public function testControllerConfigParamsAreUsed() 33 | { 34 | $this->slim->shouldReceive('config') 35 | ->once() 36 | ->with('controller.template_suffix') 37 | ->andReturnNull(); 38 | $this->slim->shouldReceive('config') 39 | ->once() 40 | ->with('controller.param_prefix') 41 | ->andReturnNull(); 42 | $this->slim->shouldReceive('config') 43 | ->once() 44 | ->with('controller.cleanup_params') 45 | ->andReturnNull(); 46 | $controller = new TestController($this->slim); 47 | $this->assertTrue(true); 48 | } 49 | 50 | public function testRenderingWorksFine() 51 | { 52 | $this->assertDefaultConstruction(); 53 | $this->slim->shouldReceive('render') 54 | ->once() 55 | ->with('rendertest.Suffix', array('foo' => 'orotound', 'bar' => 'grandios')); 56 | 57 | $controller = new TestController($this->slim); 58 | $controller->renderAction(); 59 | } 60 | 61 | public function testRedirectWorksFine() 62 | { 63 | $this->assertDefaultConstruction(); 64 | $this->slim->shouldReceive('redirect') 65 | ->once() 66 | ->with('/here'); 67 | 68 | $controller = new TestController($this->slim); 69 | $controller->redirectAction(); 70 | } 71 | 72 | public function testSingleParamLeafAccessWorks() 73 | { 74 | $this->expectOutputString("Param is foo"); 75 | $this->assertDefaultConstruction(); 76 | $request = m::mock(); 77 | $this->slim->shouldReceive('request') 78 | ->once() 79 | ->withNoArgs() 80 | ->andReturn($request); 81 | $request->shouldReceive('params') 82 | ->once() 83 | ->withNoArgs() 84 | ->andReturn(array('Some' => array('param' => 'foo'))); 85 | 86 | $controller = new TestController($this->slim); 87 | $controller->paramSingleAction(); 88 | } 89 | 90 | public function testSingleParamArrayAccessWorks() 91 | { 92 | $this->expectOutputString("Param is foobarbaz"); 93 | $this->assertDefaultConstruction(); 94 | $request = m::mock(); 95 | $this->slim->shouldReceive('request') 96 | ->once() 97 | ->withNoArgs() 98 | ->andReturn($request); 99 | $request->shouldReceive('params') 100 | ->once() 101 | ->withNoArgs() 102 | ->andReturn(array('Some' => array('attrib1' => 'foo', 'attrib2' => 'bar', 'attrib3' => 'baz'))); 103 | 104 | $controller = new TestController($this->slim); 105 | $controller->paramSingleArrayAction(); 106 | } 107 | 108 | public function testMultiParamAccessWorks() 109 | { 110 | $this->expectOutputString('{"Some.param":"foo","Other.param":"bar"}'); 111 | $this->assertDefaultConstruction(); 112 | $request = m::mock(); 113 | $this->slim->shouldReceive('request') 114 | ->once() 115 | ->withNoArgs() 116 | ->andReturn($request); 117 | $request->shouldReceive('params') 118 | ->once() 119 | ->withNoArgs() 120 | ->andReturn(array('Some' => array('param' => 'foo'), 'Other' => array('param' => 'bar'))); 121 | 122 | $controller = new TestController($this->slim); 123 | $controller->paramMultiAction(); 124 | } 125 | 126 | public function testMultiParamAccessWithRequiredParams() 127 | { 128 | $this->expectOutputString('{"Some.param":"foo","Other.param":"bar"}'); 129 | $this->assertDefaultConstruction(); 130 | $request = m::mock(); 131 | $this->slim->shouldReceive('request') 132 | ->once() 133 | ->withNoArgs() 134 | ->andReturn($request); 135 | $request->shouldReceive('get') 136 | ->once() 137 | ->withNoArgs() 138 | ->andReturn(array('Some' => array('param' => 'foo'), 'Other' => array('param' => 'bar'))); 139 | 140 | $controller = new TestController($this->slim); 141 | $controller->paramMultiMissingReqAction(); 142 | } 143 | 144 | public function testMultiParamAccessWithRequiredParamsWhichAreMissing() 145 | { 146 | $this->expectOutputString('null'); 147 | $this->assertDefaultConstruction(); 148 | $request = m::mock(); 149 | $this->slim->shouldReceive('request') 150 | ->once() 151 | ->withNoArgs() 152 | ->andReturn($request); 153 | $request->shouldReceive('get') 154 | ->once() 155 | ->withNoArgs() 156 | ->andReturn(array('Some' => array('param' => 'foo'))); 157 | 158 | $controller = new TestController($this->slim); 159 | $controller->paramMultiMissingReqAction(); 160 | } 161 | 162 | public function testMultiParamAccessWithDefaultValues() 163 | { 164 | $this->expectOutputString('{"Some.param":"foo","Other.bla":"great"}'); 165 | $this->assertDefaultConstruction(); 166 | $request = m::mock(); 167 | $this->slim->shouldReceive('request') 168 | ->once() 169 | ->withNoArgs() 170 | ->andReturn($request); 171 | $request->shouldReceive('get') 172 | ->once() 173 | ->withNoArgs() 174 | ->andReturn(array('Some' => array('param' => 'foo'))); 175 | 176 | $controller = new TestController($this->slim); 177 | $controller->paramMultiDefaultAction(); 178 | } 179 | 180 | public function testGetAllAvailableParams() 181 | { 182 | $this->expectOutputString('{"Some.param":"foo","Other":"bar"}'); 183 | $this->assertDefaultConstruction(); 184 | $request = m::mock(); 185 | $this->slim->shouldReceive('request') 186 | ->twice() 187 | ->withNoArgs() 188 | ->andReturn($request); 189 | $request->shouldReceive('params') 190 | ->twice() 191 | ->withNoArgs() 192 | ->andReturn(array('Some' => array('param' => 'foo'), 'Other' => 'bar')); 193 | 194 | $controller = new TestController($this->slim); 195 | $controller->paramGetAllAction(); 196 | } 197 | 198 | public function testGetAllAvailableParamsWithPrefix() 199 | { 200 | $this->expectOutputString('{"Some.param":"foo"}'); 201 | $this->assertDefaultConstruction('Suffix', 'data'); 202 | $request = m::mock(); 203 | $this->slim->shouldReceive('request') 204 | ->twice() 205 | ->withNoArgs() 206 | ->andReturn($request); 207 | $request->shouldReceive('params') 208 | ->twice() 209 | ->withNoArgs() 210 | ->andReturn(array('data' => array('Some' => array('param' => 'foo')), 'Other' => 'bar')); 211 | 212 | $controller = new TestController($this->slim); 213 | $controller->paramGetAllAction(); 214 | } 215 | 216 | public function testUseSimpleNoCleanup() 217 | { 218 | $this->expectOutputString('{"Some.param":"foo","Other":"bar"}'); 219 | $this->assertDefaultConstruction('Suffix', '', false); 220 | $request = m::mock(); 221 | $this->slim->shouldReceive('request') 222 | ->twice() 223 | ->withNoArgs() 224 | ->andReturn($request); 225 | $request->shouldReceive('params') 226 | ->twice() 227 | ->withNoArgs() 228 | ->andReturn(array('Some' => array('param' => 'foo'), 'Other' => 'bar')); 229 | 230 | $controller = new TestController($this->slim); 231 | $controller->paramGetAllAction(); 232 | } 233 | 234 | public function testUseSimpleCleanup() 235 | { 236 | $this->expectOutputString('{"Some.param":"foobla","Other":"bar"}'); 237 | $this->assertDefaultConstruction('Suffix', '', true); 238 | $request = m::mock(); 239 | $this->slim->shouldReceive('request') 240 | ->twice() 241 | ->withNoArgs() 242 | ->andReturn($request); 243 | $request->shouldReceive('params') 244 | ->twice() 245 | ->withNoArgs() 246 | ->andReturn(array('Some' => array('param' => 'foo'), 'Other' => 'bar')); 247 | 248 | $controller = new TestController($this->slim); 249 | $controller->paramGetAllAction(); 250 | } 251 | 252 | public function testArrayCleanup() 253 | { 254 | $this->expectOutputString('["foobar","otherNotgood"]'); 255 | $this->assertDefaultConstruction('Suffix', '', true); 256 | $controller = new TestController($this->slim); 257 | $controller->paramCleanupAction(); 258 | } 259 | 260 | 261 | protected function assertDefaultConstruction($suffix = 'Suffix', $paramPrefix = '', $cleanupParams = false) 262 | { 263 | $this->slim->shouldReceive('config') 264 | ->once() 265 | ->with('controller.template_suffix') 266 | ->andReturn($suffix); 267 | $this->slim->shouldReceive('config') 268 | ->once() 269 | ->with('controller.param_prefix') 270 | ->andReturn($paramPrefix); 271 | $this->slim->shouldReceive('config') 272 | ->once() 273 | ->with('controller.cleanup_params') 274 | ->andReturn($cleanupParams); 275 | } 276 | 277 | } 278 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/SlimTest.php: -------------------------------------------------------------------------------- 1 | setUrl('/bla'); 18 | $this->app->addRoutes(array( 19 | '/bla' => array('get' => 'Controller:index'), 20 | '/alb' => array('get' => 'Controller:index') 21 | )); 22 | 23 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 24 | // $this->assertTrue($this->app->router->hasNamedRoute('Controller:index')); 25 | $this->assertEquals('/bla', $this->app->urlFor('Controller:index')); 26 | } 27 | 28 | public function testAddingroutesWithOldSyntaxWithoutMiddlewares() 29 | { 30 | $this->setUrl('/bla'); 31 | $this->app->addRoutes(array( 32 | '/bla' => array('Controller:index'), 33 | )); 34 | 35 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 36 | } 37 | 38 | public function testAddRoutesWithOldSyntaxWithoutMiddlewareArray() 39 | { 40 | $this->setUrl('/'); 41 | $this->app->addRoutes(array( 42 | '/' => array('Home:index', function() { 43 | // 44 | }) 45 | )); 46 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 47 | } 48 | 49 | public function testAddRoutesWithOldSyntaxWithMiddlewareArray() 50 | { 51 | $this->setUrl('/'); 52 | $this->app->addRoutes(array( 53 | '/' => array('Home:index', array(function() { 54 | // 55 | })) 56 | )); 57 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 58 | } 59 | 60 | public function testAddSimpleRoutes() 61 | { 62 | $this->setUrl('/'); 63 | $this->app->addRoutes(array( 64 | '/' => 'Controller:index', 65 | )); 66 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 67 | 68 | $this->setUrl('/foo'); 69 | $this->assertEquals(0, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 70 | 71 | $this->setUrl('/other'); 72 | 73 | $this->app->addRoutes(array( 74 | '/other' => 'Controller:other', 75 | )); 76 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 77 | } 78 | 79 | public function testAddRoutesWithVariables() 80 | { 81 | $this->setUrl('/hello/you'); 82 | $this->app->addRoutes(array( 83 | '/hello/:name' => 'Controller:index', 84 | )); 85 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 86 | } 87 | 88 | public function testAddRoutesInExtendedFormat() 89 | { 90 | $this->setUrl('/bla'); 91 | $this->app->addRoutes(array( 92 | '/bla' => array('get' => 'Controller:index') 93 | )); 94 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 95 | } 96 | 97 | /** 98 | * @expectedException \InvalidArgumentException 99 | * @expectedExceptionMessage Malformed class action for 'Controller:index:foo'. Use 'className:methodName' format. 100 | */ 101 | public function testFailToAddInvalidClassMethodFormat() 102 | { 103 | $this->setUrl('/bla'); 104 | $this->app->addRoutes(array( 105 | '/bla' => 'Controller:index:foo' 106 | )); 107 | } 108 | 109 | public function testGlobalMiddlewareIsAddedToRoute() 110 | { 111 | $this->setUrl('/bla'); 112 | $this->app->addRoutes(array( 113 | '/bla' => 'Controller:index' 114 | ), function() { 115 | return false; 116 | }); 117 | 118 | /** @var \Slim\Route[] $routes */ 119 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 120 | $this->assertEquals(1, count($routes)); 121 | 122 | $middleware = $routes[0]->getMiddleware(); 123 | $this->assertInternalType('array', $middleware); 124 | $this->assertSame(1, count($middleware)); 125 | } 126 | 127 | public function testGlobalMiddlewareIsAddedToRouteAsArray() 128 | { 129 | $middlewares = array( 130 | function() { return false; }, 131 | function() { return false; } 132 | ); 133 | 134 | $this->setUrl('/bla'); 135 | $this->app->addRoutes(array( 136 | '/bla' => 'Controller:index' 137 | ), $middlewares); 138 | 139 | /** @var \Slim\Route[] $routes */ 140 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 141 | $this->assertEquals(1, count($routes)); 142 | 143 | $middleware = $routes[0]->getMiddleware(); 144 | $this->assertInternalType('array', $middleware); 145 | $this->assertSame(2, count($middleware)); 146 | } 147 | 148 | public function testLocalMiddlewareIsAddedToRoute() 149 | { 150 | $this->setUrl('/bla'); 151 | $this->app->addRoutes(array( 152 | '/bla' => array('get' => array('Controller:index', function() { 153 | return false; 154 | })) 155 | )); 156 | 157 | /** @var \Slim\Route[] $routes */ 158 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 159 | $this->assertEquals(1, count($routes)); 160 | 161 | $middleware = $routes[0]->getMiddleware(); 162 | $this->assertInternalType('array', $middleware); 163 | $this->assertSame(1, count($middleware)); 164 | } 165 | 166 | public function testArrayOfLocalMiddlewareIsAddedToRoute() 167 | { 168 | $middlewares = array( 169 | function() { return false; }, 170 | function() { return false; } 171 | ); 172 | 173 | $this->setUrl('/bla'); 174 | $this->app->addRoutes(array( 175 | '/bla' => array('get' => array('Controller:index', $middlewares)) 176 | )); 177 | 178 | /** @var \Slim\Route[] $routes */ 179 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 180 | $this->assertEquals(1, count($routes)); 181 | 182 | $middleware = $routes[0]->getMiddleware(); 183 | $this->assertInternalType('array', $middleware); 184 | $this->assertSame(2, count($middleware)); 185 | } 186 | 187 | public function testLocalMiddlewaresAreAddedToRoute() 188 | { 189 | $middlewares = array( 190 | function() { return false; }, 191 | function() { return false; } 192 | ); 193 | 194 | $this->setUrl('/bla'); 195 | $this->app->addRoutes(array( 196 | '/bla' => array('get' => array('Controller:index', $middlewares[0], $middlewares[1])) 197 | )); 198 | 199 | /** @var \Slim\Route[] $routes */ 200 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 201 | $this->assertEquals(1, count($routes)); 202 | 203 | $middleware = $routes[0]->getMiddleware(); 204 | $this->assertInternalType('array', $middleware); 205 | $this->assertSame(2, count($middleware)); 206 | } 207 | 208 | public function testGlobalAndLocalMiddlewareIsAddedToRoute() 209 | { 210 | $this->setUrl('/bla'); 211 | $this->app->addRoutes(array( 212 | '/bla' => array('get' => array('Controller:index', function() { 213 | return false; 214 | })) 215 | ), array(function() { 216 | return false; 217 | }, function() { 218 | return false; 219 | })); 220 | 221 | /** @var \Slim\Route[] $routes */ 222 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 223 | $this->assertEquals(1, count($routes)); 224 | 225 | $middleware = $routes[0]->getMiddleware(); 226 | $this->assertInternalType('array', $middleware); 227 | $this->assertSame(3, count($middleware)); 228 | } 229 | 230 | /** 231 | * @expectedException \InvalidArgumentException 232 | * @expectedExceptionMessage Http method 'FOO' is not supported. 233 | */ 234 | public function testFailToAddRouteForUnsupportedHttpMethod() 235 | { 236 | $this->setUrl('/bla'); 237 | $this->app->addRoutes(array( 238 | '/bla' => array('foo' => 'Controller:index') 239 | )); 240 | } 241 | 242 | public function testRouteCallbacksAreFiredOnDispatch() 243 | { 244 | $this->expectOutputString('What is up?'); 245 | $this->setUrl('/bla'); 246 | $this->app->addRoutes(array( 247 | '/bla' => 'Test:index' 248 | )); 249 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 250 | $route->dispatch(); 251 | } 252 | 253 | public function testEmptyButNotNullMethodSuffixAccepted() 254 | { 255 | $this->expectOutputString('Yes, I was called'); 256 | $this->setUrl('/bla', '', array( 257 | 'controller.method_suffix' => '' 258 | )); 259 | $this->app->addRoutes(array( 260 | '/bla' => 'Test:notSuffixedMethod' 261 | )); 262 | list($route) = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 263 | $route->dispatch(); 264 | } 265 | 266 | public function testAddControllerRoute() 267 | { 268 | $this->setUrl('/'); 269 | $this->app->addControllerRoute( 270 | '/', 'Controller:index' 271 | )->via('GET'); 272 | 273 | $this->assertEquals(1, count($this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()))); 274 | } 275 | 276 | public function testAddControllerRouteWithMiddleware() 277 | { 278 | $this->setUrl('/'); 279 | $this->app->addControllerRoute( 280 | '/', 'Controller:index', array( 281 | function() { 282 | return false; 283 | }, 284 | ) 285 | )->via('GET'); 286 | 287 | /** @var \Slim\Route[] $routes */ 288 | $routes = $this->app->router()->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()); 289 | $this->assertEquals(1, count($routes)); 290 | 291 | $middleware = $routes[0]->getMiddleware(); 292 | $this->assertInternalType('array', $middleware); 293 | $this->assertSame(1, count($middleware)); 294 | } 295 | 296 | public function testNamedRoutes() 297 | { 298 | $this->setUrl('/'); 299 | $this->app->addRoutes(array( 300 | '/' => 'Controller:index', 301 | '/bla' => 'Bla:Index', 302 | '/something/:id' => 'Something:show' 303 | )); 304 | 305 | $this->assertEquals('/', $this->app->urlFor('Controller:index')); 306 | $this->assertEquals('/bla', $this->app->urlFor('Bla:Index')); 307 | $this->assertEquals('/something/:id', $this->app->urlFor('Something:show')); 308 | } 309 | 310 | /** 311 | * @expectedException \RuntimeException 312 | * @expectedExceptionMessage Named route not found for name: this is not a named route 313 | */ 314 | public function testNamedRoutesThrowsExceptionIfLookingForARouteThatDoesNotExist() 315 | { 316 | $this->setUrl('/'); 317 | $this->app->addRoutes(array( 318 | '/' => 'Controller:index', 319 | '/bla' => 'Bla:Index', 320 | '/something/:id' => 'Something:show' 321 | )); 322 | 323 | $this->assertEquals('/', $this->app->urlFor('this is not a named route')); 324 | } 325 | 326 | public function testServiceControllersAreFetched() 327 | { 328 | $this->expectOutputString("What is up?"); 329 | 330 | $config = array( 331 | 'controller.class_prefix' => '', 332 | 'controller.class_suffix' => '', 333 | ); 334 | $this->setUrl('/', '', $config); 335 | $app = $this->app; 336 | $app->container->singleton('TestController', function () use ($app) { 337 | return new TestController($app); 338 | }); 339 | 340 | $route = $this->app->addControllerRoute( 341 | '/', 'TestController:index' 342 | )->via('GET'); 343 | 344 | // If the route could be dispatched, then the service was found 345 | $result = $route->dispatch(); 346 | $this->assertTrue($result); 347 | } 348 | 349 | public function testServiceControllersAreFetchedWithParams() 350 | { 351 | $this->expectOutputString("What is up foo?"); 352 | 353 | $config = array( 354 | 'controller.class_prefix' => '', 355 | 'controller.class_suffix' => '', 356 | ); 357 | $this->setUrl('/', '', $config); 358 | $app = $this->app; 359 | $app->container->singleton('TestController', function () use ($app) { 360 | return new TestController($app); 361 | }); 362 | 363 | $app->addRoutes(array( 364 | '/another/:name' => 'TestController:hello' 365 | )); 366 | $route = $app->router()->getNamedRoute('TestController:hello'); 367 | $route->setParams(array('name' => 'foo')); 368 | $this->assertTrue($route->dispatch()); 369 | } 370 | 371 | public function testServiceControllersAreFetchedEvenIfTheirNameIsAnInvalidPHPClassName() 372 | { 373 | $this->expectOutputString("What is up?"); 374 | 375 | $config = array( 376 | 'controller.class_prefix' => '', 377 | 'controller.class_suffix' => '', 378 | ); 379 | $this->setUrl('/', '', $config); 380 | $app = $this->app; 381 | $app->container->singleton('String\\Controller', function () use ($app) { 382 | return new TestController($app); 383 | }); 384 | 385 | $route = $this->app->addControllerRoute( 386 | '/', 'String\\Controller:index' 387 | )->via('GET'); 388 | 389 | // If the route could be dispatched, then the service was found 390 | $result = $route->dispatch(); 391 | $this->assertTrue($result); 392 | } 393 | 394 | } 395 | -------------------------------------------------------------------------------- /tests/SlimController/Tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 'GET', 38 | 'REMOTE_ADDR' => '127.0.0.1', 39 | 'SCRIPT_NAME' => '', //<-- Physical 40 | 'PATH_INFO' => $path, //<-- Virtual 41 | 'QUERY_STRING' => $params, 42 | 'SERVER_NAME' => 'slim', 43 | 'SERVER_PORT' => 80, 44 | 'slim.url_scheme' => 'http', 45 | 'slim.input' => '', 46 | 'slim.errors' => fopen('php://stderr', 'w'), 47 | 'HTTP_HOST' => 'slim' 48 | )); 49 | $this->env = Environment::getInstance(); 50 | $this->req = new Request($this->env); 51 | $this->res = new Response(); 52 | $this->app = new Slim(array_merge(array( 53 | 'controller.class_prefix' => '\\SlimController\\Tests\\Fixtures\\Controller', 54 | 'controller.class_suffix' => 'Controller', 55 | 'controller.method_suffix' => 'Action', 56 | 'controller.template_suffix' => 'php', 57 | 'templates.path' => __DIR__ . '/Fixtures/templates' 58 | ), $config)); 59 | } 60 | } -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | add('SlimController\\Tests\\', __DIR__); 6 | $loader->register(); 7 | 8 | /*include 'SlimControllerUnitTestCase.php'; 9 | include 'Controller/Test.php';*/ --------------------------------------------------------------------------------