Compare commits

...

209 Commits

Author SHA1 Message Date
Simon Sessingø 0090c167bb Merge pull request #287 from skipperbent/v3-development
Response->json now accepts either array or \JsonSerializable (issue: #284)
2017-08-31 13:05:14 +02:00
Simon Sessingø ae68598024 Response->json now accepts either array or \JsonSerializable (issue: 2017-08-31 12:03:17 +01:00
Simon Sessingø 7362b748af Merge pull request #282 from skipperbent/v3-development
V3 development
2017-08-24 16:53:20 +02:00
Simon Sessingø 4fe85d6568 Merge pull request #281 from skipperbent/v3-fix-urldecode
Urldecode is now used on all urls in Uri class (issue: #268)
2017-08-24 16:53:04 +02:00
Simon Sessingø c82d91375c Urldecode is now used on all urls in Uri class (issue: #268) 2017-08-24 15:50:13 +01:00
Simon Sessingø e774122b1e Merge pull request #279 from skipperbent/v3-development
V3 development
2017-08-24 03:12:57 +02:00
Simon Sessingø e8aceb291c Merge pull request #278 from skipperbent/v3-fix-iis-encoding
Ensured that Request class is using unencoded-url header to avoid encoding issues on IIS (issue: #268)
2017-08-24 03:12:48 +02:00
Simon Sessingø 957a382248 Ensured that Request class is using unencoded-url header to avoid encoding issues on IIS (issue: #268) 2017-08-24 02:05:18 +01:00
Simon Sessingø 48e2e3f9bc Merge pull request #276 from skipperbent/v3-development
V3 development
2017-08-23 23:50:18 +02:00
Simon Sessingø f95e12c49c Merge pull request #275 from skipperbent/fix-unicode
Added unicode parameter regex support.
2017-08-23 23:50:04 +02:00
Simon Sessingø 9f509ac818 Added unicode parameter regex support. 2017-08-23 22:49:35 +01:00
Simon Sessingø 3b4d23e9ae Merge pull request #273 from skipperbent/v3-development
Version 3.4
2017-08-23 22:30:41 +02:00
Simon Sessingø b3e99a2283 Merge pull request #267 from skipperbent/fix-url
Fixed: return / if all parameters are empty in getUrl method.
2017-08-23 22:17:15 +02:00
Simon Sessingø c1aa5782a1 Merge pull request #271 from skipperbent/v3-feature-uri
Added Uri class which can be used to parse urls.
2017-08-23 22:17:04 +02:00
Simon Sessingø 387d9710d8 Merge pull request #272 from jatubio/patch-1
Add IIS web.config file example
2017-08-23 22:16:53 +02:00
Simon Sessingø fd098266f7 Merge pull request #266 from zaingithub/patch-1
Update README.md
2017-08-23 22:16:24 +02:00
Simon Sessingø c7473938c5 Changed xxx to web.config 2017-08-23 22:09:55 +02:00
Simon Sessingø 65c811356d Fixed url parsing for unicode characters. 2017-08-23 21:04:11 +01:00
Simon Sessingø ea255baec3 Merge branch 'v3-fix-url-encoding' into v3-feature-uri 2017-08-23 20:44:57 +01:00
Simon Sessingø acf37c4023 Updated Uri class. 2017-08-23 20:41:49 +01:00
Juan Antonio Tubio 6fb92d7cae Add IIS web.config file example 2017-08-23 17:28:14 +02:00
Simon Sessingø e84c8c2f02 Uri is now always urldecoded in Request class to ensure compability with
most webservers (issue: #268).
2017-08-23 16:13:44 +01:00
Simon Sessingø 7c970c442c Added Uri class which can be used to parse urls. 2017-08-23 16:10:15 +01:00
Simon Sessingø 4cd1e8e069 Fixed: return / if all parameters are empty in $router->getUrl method. 2017-08-22 17:18:48 +01:00
zaingithub 8720e732e1 Update README.md
Update section : ## Handling 404, 403 and other errors

$exception->getCode to $exception->getCode()
2017-08-20 12:47:27 +07:00
Simon Sessingø 7e8cb91f68 Updated documentation 2017-08-19 16:21:55 +01:00
Simon Sessingø bc67038e11 Added helpers.php file
- Added updated helpers.php file
- Updated helpers section in documentation.
2017-08-19 13:48:47 +01:00
Simon Sessingø e31d8af2f7 Merge pull request #264 from skipperbent/v3
V3
2017-08-18 20:32:33 +02:00
Simon Sessingø 9f285fd0ce Merge pull request #263 from skipperbent/v3-development
V3 development
2017-08-18 20:32:21 +02:00
Simon Sessingø b7f5d31544 Fixed double / when calling findUrl on routes with the first
parameter optional.
2017-08-17 23:31:27 +01:00
Simon Sessingø 5086347802 Bugfix: fixed using empty value in url still parsing current
parameters.
2017-08-13 18:01:48 +01:00
Simon Sessingø 26f89213a2 Merge pull request #260 from skipperbent/v3
V3
2017-08-13 04:14:17 +02:00
Simon Sessingø bb7991afdc Merge pull request #259 from skipperbent/v3-development
Version 3.3.5
2017-08-13 04:14:04 +02:00
Simon Sessingø 796d01bc25 Merge pull request #258 from skipperbent/v3-fixes
Fixes and development
2017-08-13 04:13:40 +02:00
Simon Sessingø 74187ee326 Fixes and development
- `$parameter` argument in `findUrl` method now supports both string,
array and null value to avoid confusion.

- Using return value in callbacks now displays value (issue: #257)
2017-08-13 03:06:27 +01:00
Simon Sessingø f090d6c038 Merge pull request #256 from skipperbent/v3
V3
2017-08-07 22:23:03 +02:00
Simon Sessingø 6e859e11ab Merge pull request #255 from skipperbent/v3-development
V3 development
2017-08-07 22:22:34 +02:00
Simon Sessingø 6aa38cfa4c Merge pull request #254 from skipperbent/v3-url-match-fix
Fixed wrong url matching on some paths (issue: #253 - thanks @alejoloe007jb)
2017-08-07 22:20:32 +02:00
Simon Sessingø 62f0075cf3 Fixed wrong url matching on some paths (issue: #253 - thanks @alejoloe007jb) 2017-08-07 22:18:36 +02:00
Simon Sessingø 6890b60737 Merge pull request #252 from skipperbent/v3
V3
2017-08-01 21:30:52 +02:00
Simon Sessingø a40f81d5fc Merge pull request #251 from skipperbent/v3-development
V3 development
2017-08-01 21:30:42 +02:00
Simon Sessingø a5527a0e8c Merge pull request #250 from skipperbent/bugfix-urlmatch
Bugfix urlmatch
2017-08-01 21:30:13 +02:00
Simon Sessingø 3c73de866e Added code-comments. 2017-08-01 21:25:44 +02:00
Simon Sessingø 883d8a6b0e Fixes for issue #248 2017-08-01 21:09:18 +02:00
Simon Sessingø 3a7b27796a Url matching fixes 2017-08-01 18:29:47 +02:00
Simon Sessingø 1e07140865 Merge pull request #247 from skipperbent/v3
V3
2017-07-18 11:28:33 +02:00
Simon Sessingø 4cca5186f3 Merge pull request #246 from skipperbent/v3-development
V3 development
2017-07-18 11:28:19 +02:00
Simon Sessingø 5437420175 Merge pull request #245 from skipperbent/php5-5-compatibility
Fixed PHP 5.5 compatibility (issue: #244 - thanks @thexeos)
2017-07-18 11:27:59 +02:00
Simon Sessingø 410fa3c9f5 Fixed PHP 5.5 compatibility (issue: #244 - thanks @thexeos) 2017-07-18 11:26:45 +02:00
Simon Sessingø be20fe4dd1 Updated composer.json tags. 2017-07-08 12:20:49 +02:00
Simon Sessingø bc03490100 Merge pull request #243 from skipperbent/v3
V3
2017-07-08 12:03:42 +02:00
Simon Sessingø 0947f6746e Merge pull request #242 from skipperbent/v3-development
V3 development
2017-07-08 12:03:05 +02:00
Simon Sessingø 31c8710ce7 Merge pull request #241 from skipperbent/v-3-3-1
Version 3.3.1
2017-07-08 12:02:41 +02:00
Simon Sessingø 1ac7761d35 Development
- Optimized `.gitignore`.
- Renamed `XSRF-TOKEN` constant to `CSRF-TOKEN` in `CsrfToken`.
2017-07-08 11:56:57 +02:00
Simon Sessingø 9eb7c5c13c Removed 'name' as it's set as the default value when calling the $getItem function. 2017-07-08 11:49:05 +02:00
Simon Sessingø 5151461a02 Added setMiddleware deprecated method in Route class. 2017-07-08 11:42:27 +02:00
Simon Sessingø b07348a3df Development
- Removed temporary `RouterException` class.
- Added object-types to parameters in `CallbackExceptionHandler` and `SimpleRouter` classes.
- Router now renders groups even if callback is null.
- Renamed `setMiddleware` to `addMiddleware` in `Route` class and `IRoute` interface.
- `addMiddleware` now accept both object and class strings in `Route` class.
- `addExceptionHandler` now accept both object and class strings in `RouteGroup` class.
- Added unit-test for rewrite-exception message change: `testRewriteExceptionMessage` in `RouterRewriteTest`.
- Fixed typo: renamed `testSimularUrls` to `testSimilarUrls` in `RouterUrlTest`.
2017-07-08 11:21:18 +02:00
Simon Sessingø d411b31cc2 Changed message-text thrown in NotFoundHttpException to show redirected routes (issue: #240) 2017-07-06 15:46:09 +02:00
Simon Sessingø ca381d445f Development
- Changed router so it supports both string and object as exception handlers.
- Added `Router::error($callback)` method to `Router` class (issue #238).
- Fixed issues calling `getController` and `getMethod` when callback is an object (issue #239).
- Updated documentation to reflect new changes.
- Added `addExceptionHandler` to `IGroupRoute` interface and `RouteGroup` class.
- Other minor bugfixes and optimisations.
2017-07-06 15:25:04 +02:00
Simon Sessingø 2c61cef7ad Merge pull request #237 from skipperbent/v3
V3
2017-05-09 07:06:33 +02:00
Simon Sessingø 98ee60859f Merge pull request #236 from skipperbent/v3-development
Development
2017-05-09 07:06:18 +02:00
Simon Sessingø 9dd80dd1d9 Development
- Fixed global regex match not working properly.
- Feature: added option to change regular expression used for parameters on routes.
- Added unit-tests for custom parameter regular expression.
- Updated documentation to reflect new features.
2017-05-09 06:43:26 +02:00
Simon Sessingø 3f9ab73f7f Merge pull request #235 from skipperbent/v3
V3
2017-05-09 02:52:06 +02:00
Simon Sessingø fef997422e Merge pull request #234 from skipperbent/v3-development
V3 development
2017-05-09 02:51:58 +02:00
Simon Sessingø 8901e7c125 Development
- Added check in `CsrfToken` class to ensure that IV generation is strong and secure.
- Minor optimisations mostly related to PHPDocs and PHPStorm code-inspection.
2017-05-09 02:49:41 +02:00
Simon Sessingø 50e8926272 Added .htaccess example to documentation (issue #232) 2017-05-09 02:31:01 +02:00
Simon Sessingø e44d6bc30b Merge pull request #231 from skipperbent/v3
V3
2017-03-06 02:56:50 +01:00
Simon Sessingø 27ff761d18 Merge pull request #230 from skipperbent/v3-development
V3 development
2017-03-06 02:56:37 +01:00
Simon Sessingø 0a58d36606 Development
- Fixed: `RouteController` not matching certain urls.
- Made `RouteResource` more strict in url-matching.
- Added PHPUnit `RouterControllerTest` class.
- Fixed merged `testSimularUrls` method in `RouterUrlTest`.
2017-03-06 02:53:44 +01:00
Simon Sessingø db024b9588 Added simular routes PHPUnit test 2017-03-06 02:21:13 +01:00
Simon Sessingø 3f61c90749 Merge pull request #229 from skipperbent/v3
V3
2017-03-05 17:10:35 +01:00
Simon Sessingø 94d0764631 Merge pull request #228 from skipperbent/v3-development
Development
2017-03-05 17:10:27 +01:00
Simon Sessingø ff3f1bdcdd Development
- Fixed issue #227 causing custom resource-routes not to be loaded after latest update.
- Optimized `RouteResource` class.
- Renamed `IRestController` to `IResourceController`.
- Added unit-tests for RouterResource.
- Simplified unit-tests with the `TestRouter` custom router class.
2017-03-05 17:09:46 +01:00
Simon Sessingø e4e632dca9 Merge pull request #226 from skipperbent/v3
V3
2017-03-01 03:39:46 +01:00
Simon Sessingø a5c4a1f721 Merge pull request #223 from skipperbent/v3
V3
2017-02-15 03:29:24 +01:00
Simon Sessingø 0bc7fa7bd5 Merge pull request #220 from skipperbent/v3
V3
2017-02-13 06:47:36 +01:00
Simon Sessingø eb036ded3b Merge pull request #218 from skipperbent/v3
V3
2017-02-12 20:48:12 +01:00
Simon Sessingø debe080181 Merge pull request #215 from skipperbent/v3
Merge pull request #214 from skipperbent/v3-development
2017-02-09 13:34:46 +01:00
Simon Sessingø dd99e1d488 Merge pull request #213 from skipperbent/v3-development
Optimisations
2017-02-09 13:34:03 +01:00
Simon Sessingø 1c07311c5d Merge pull request #212 from skipperbent/v3
Version 3
2017-02-09 13:24:44 +01:00
Simon Sessingø 801c84eb05 Merge pull request #210 from skipperbent/v2
V2
2017-02-01 07:52:38 +01:00
Simon Sessingø ed98519152 Merge pull request #209 from skipperbent/v2-development
Fixed getExtension method in InputFile retuning empty value.
2017-02-01 07:52:29 +01:00
Simon Sessingø 55d031e152 Merge pull request #208 from skipperbent/v2
V2
2017-01-19 18:41:55 +01:00
Simon Sessingø 8509062e00 Merge pull request #207 from skipperbent/v2-development
Development
2017-01-19 18:41:43 +01:00
Simon Sessingø 4b4ab906fb Merge pull request #205 from skipperbent/v2
V2
2016-11-28 14:14:38 +01:00
Simon Sessingø 9617cacc31 Merge pull request #204 from skipperbent/v2-development
getRoute optimisations.
2016-11-28 14:14:29 +01:00
Simon Sessingø 54a824ce44 Merge pull request #203 from skipperbent/v2
V2
2016-11-28 14:01:10 +01:00
Simon Sessingø 99088719ed Merge pull request #202 from skipperbent/v2-development
`getUrl` will now use default-parameter value if specifically set to null when using `url()`.
2016-11-28 14:00:59 +01:00
Simon Sessingø 2062ff4189 Merge pull request #201 from skipperbent/v2
V2
2016-11-28 06:45:16 +01:00
Simon Sessingø 3e41ee28b6 Merge pull request #200 from skipperbent/v2-development
Optimised route-match behavior
2016-11-28 06:45:05 +01:00
Simon Sessingø 13a5f40cd0 Merge pull request #199 from skipperbent/v2
V2
2016-11-28 05:53:36 +01:00
Simon Sessingø 751b4444ae Merge pull request #198 from skipperbent/v2-development
Fixed parameters not merged with default values
2016-11-28 05:53:26 +01:00
Simon Sessingø 351f7a01e8 Merge pull request #197 from skipperbent/v2
V2
2016-11-28 05:26:19 +01:00
Simon Sessingø 8cd42a2c4b Merge pull request #196 from skipperbent/v2-development
2.6.0
2016-11-28 05:26:04 +01:00
Simon Sessingø 1496878ae9 Merge pull request #195 from skipperbent/v2
V2
2016-11-26 05:22:17 +01:00
Simon Sessingø e8e1471bab Merge pull request #194 from skipperbent/v2-development
Input optimisations
2016-11-26 05:22:02 +01:00
Simon Sessingø b3f2e5f812 Merge pull request #193 from skipperbent/v2
V2
2016-11-26 05:03:45 +01:00
Simon Sessingø 4de1498723 Merge pull request #192 from skipperbent/v2-development
V2 development
2016-11-26 05:03:36 +01:00
Simon Sessingø a60fa9f919 Merge pull request #191 from skipperbent/v2
V2
2016-11-25 18:28:37 +01:00
Simon Sessingø ea243f2c89 Merge pull request #190 from skipperbent/v2-development
Development
2016-11-25 18:28:26 +01:00
Simon Sessingø ce6f34f4d4 Merge pull request #189 from skipperbent/v2
V2
2016-11-25 12:55:17 +01:00
Simon Sessingø 56653568e4 Merge pull request #188 from skipperbent/v2-development
Development
2016-11-25 12:55:08 +01:00
Simon Sessingø 2868ffe023 Merge pull request #187 from skipperbent/v2
V2
2016-11-25 03:29:01 +02:00
Simon Sessingø 5d330643e7 Merge pull request #186 from skipperbent/v2-development
Development
2016-11-25 03:28:49 +02:00
Simon Sessingø 8ab52364da Merge pull request #185 from skipperbent/v2
V2
2016-11-25 03:06:03 +02:00
Simon Sessingø 57aa8eac1e Merge pull request #184 from skipperbent/v2-development
Fixed Exception when using Request
2016-11-25 03:05:17 +02:00
Simon Sessingø 110bc2afcf Merge pull request #183 from skipperbent/v2
V2
2016-11-25 02:58:55 +02:00
Simon Sessingø 4efc72d013 Merge pull request #182 from skipperbent/v2-development
Development
2016-11-25 02:58:43 +02:00
Simon Sessingø a92a4cdf0d Merge pull request #181 from skipperbent/v2
V2
2016-11-24 14:51:16 +02:00
Simon Sessingø 49fc991f9a Merge pull request #180 from skipperbent/v2-development
Updated documentation
2016-11-24 14:51:07 +02:00
Simon Sessingø 0a4c78cf64 Merge pull request #179 from skipperbent/v2
V2
2016-11-24 14:45:06 +02:00
Simon Sessingø 20353c6e4d Merge pull request #178 from skipperbent/v2-development
Updated documentation to use Demo instead of MyWebsite
2016-11-24 14:44:56 +02:00
Simon Sessingø 6706d86784 Merge pull request #177 from skipperbent/v2
V2
2016-11-24 13:19:00 +02:00
Simon Sessingø 4c62f86a26 Merge pull request #176 from skipperbent/v2-development
Fixed HttpException not thrown as NotFoundHttpException
2016-11-24 13:18:52 +02:00
Simon Sessingø 20c1e0ef69 Merge pull request #175 from skipperbent/v2
V2
2016-11-24 11:06:10 +02:00
Simon Sessingø 6445746324 Merge pull request #174 from skipperbent/v2-development
Optimisations + bugfixes
2016-11-24 11:05:57 +02:00
Simon Sessingø 1a2921acb4 Merge pull request #173 from skipperbent/v2-development
Development
2016-11-21 09:30:58 +02:00
Simon Sessingø fe560a9ba5 Merge pull request #172 from skipperbent/v2
V2
2016-11-21 09:04:32 +02:00
Simon Sessingø 258d9d05c7 Merge pull request #171 from skipperbent/v2-development
Enhancements
2016-11-21 09:04:22 +02:00
Simon Sessingø c522801c28 Merge pull request #170 from skipperbent/v2
V2
2016-11-21 05:28:00 +02:00
Simon Sessingø 7e7319de06 Merge pull request #169 from skipperbent/v2-development
Fixed // on currentRoute urls.
2016-11-21 05:27:53 +02:00
Simon Sessingø 9d275d6d3b Merge pull request #168 from skipperbent/v2-development
Bugfixes
2016-11-21 05:08:12 +02:00
Simon Sessingø 531b35532b Merge pull request #167 from skipperbent/v2-development
Bugfixes
2016-11-21 05:07:59 +02:00
Simon Sessingø e6dd9f3f55 Merge pull request #166 from skipperbent/v2
V2
2016-11-21 04:09:35 +02:00
Simon Sessingø c258f937e8 Merge pull request #165 from skipperbent/v2-development
V 2.4.0 development
2016-11-21 04:09:26 +02:00
Simon Sessingø e803b1ca5c Merge pull request #164 from skipperbent/v2
V2
2016-11-19 21:13:12 +02:00
Simon Sessingø 88d58cd7b7 Merge pull request #163 from skipperbent/v2-development
Fixed: wrong argument-type in getUrl method
2016-11-19 21:12:57 +02:00
Simon Sessingø 45faf9830e Merge pull request #162 from skipperbent/v2
V2
2016-11-19 20:41:38 +02:00
Simon Sessingø d04c74ccad Merge pull request #161 from skipperbent/v2-development
V2 development
2016-11-19 20:41:26 +02:00
Simon Sessingø c915c0386a Merge pull request #160 from skipperbent/v2
V2
2016-11-19 10:16:06 +02:00
Simon Sessingø 02809a4daf Merge pull request #159 from skipperbent/v2-development
Bugfixes
2016-11-19 10:15:56 +02:00
Simon Sessingø 30479b15ca Merge pull request #158 from skipperbent/v2
V2
2016-11-19 09:47:29 +02:00
Simon Sessingø da6b5af19f Merge pull request #157 from skipperbent/v2-development
Bugfixes
2016-11-19 09:47:19 +02:00
Simon Sessingø 4dde51e833 Merge pull request #156 from skipperbent/v2
V2
2016-11-19 07:02:34 +02:00
Simon Sessingø 914ec9d1b7 Merge pull request #155 from skipperbent/v2-development
Small optimisations
2016-11-19 07:02:23 +02:00
Simon Sessingø 961a4d0e94 Merge pull request #154 from skipperbent/v2
V2
2016-11-19 06:25:23 +02:00
Simon Sessingø 5f72755a98 Merge pull request #153 from skipperbent/v2-development
V2 development
2016-11-19 06:25:08 +02:00
Simon Sessingø 2216090a5f Merge pull request #152 from skipperbent/v2
V2
2016-11-17 19:01:25 +02:00
Simon Sessingø 41d15d3acd Merge pull request #151 from skipperbent/v2-development
Re-added missing methods from version 1.
2016-11-17 19:01:17 +02:00
Simon Sessingø d467f60e55 Merge pull request #150 from skipperbent/v2
V2
2016-11-17 17:33:59 +02:00
Simon Sessingø ded9c8ebe0 Merge pull request #149 from skipperbent/v2-development
Updated documentation
2016-11-17 17:33:49 +02:00
Simon Sessingø c30ae6b098 Merge pull request #148 from skipperbent/v2
V2
2016-11-17 17:25:54 +02:00
Simon Sessingø 394f7beb8b Merge pull request #147 from skipperbent/v2-development
V2 development
2016-11-17 17:25:30 +02:00
Simon Sessingø c93308c8e1 Merge pull request #146 from skipperbent/v2
V2
2016-11-17 16:04:53 +02:00
Simon Sessingø baab004482 Merge pull request #145 from skipperbent/v2-development
Added default null parameter value to RouterController and RouterResource
2016-11-17 16:04:38 +02:00
Simon Sessingø c3241012af Merge pull request #144 from skipperbent/v2
V2
2016-11-17 15:21:32 +02:00
Simon Sessingø 00c0cad211 Merge pull request #143 from skipperbent/v2-development
Bugfix: set parameters to null when new url is set
2016-11-17 15:21:24 +02:00
Simon Sessingø 9e2ba2674b Merge pull request #142 from skipperbent/v2
V2
2016-11-17 06:37:11 +02:00
Simon Sessingø c6e85676da Merge pull request #141 from skipperbent/v2-development
Bugfixes
2016-11-17 06:37:03 +02:00
Simon Sessingø 4d18f33a81 Merge pull request #140 from skipperbent/v2
V2
2016-11-17 05:03:39 +02:00
Simon Sessingø 5a74c9d27d Merge pull request #139 from skipperbent/v2-development
Development
2016-11-17 05:03:30 +02:00
Simon Sessingø 9d98b2da4c Merge pull request #138 from skipperbent/v2
V2
2016-11-16 16:16:33 +02:00
Simon Sessingø b5eef6f3ee Merge pull request #137 from skipperbent/v2-development
Bugfixes
2016-11-16 16:16:22 +02:00
Simon Sessingø 6930864e7e Merge pull request #136 from skipperbent/v2
V2
2016-11-16 15:32:45 +02:00
Simon Sessingø ad0eceb814 Merge pull request #135 from skipperbent/v2-development
Bugfixes
2016-11-16 15:32:32 +02:00
Simon Sessingø f3f129ae0b Merge pull request #134 from skipperbent/v2
V2
2016-11-15 09:47:07 +02:00
Simon Sessingø 4bec2bc5fb Merge pull request #133 from skipperbent/v2-development
Csrf bugfixes
2016-11-15 09:46:54 +02:00
Simon Sessingø 85b9fac21e Merge pull request #132 from skipperbent/v2
V2
2016-11-15 08:13:22 +02:00
Simon Sessingø 4f47463497 Merge pull request #131 from skipperbent/v2-development
V2 development
2016-11-15 08:13:09 +02:00
Simon Sessingø 0c93633d13 Merge pull request #130 from skipperbent/v2
V2
2016-11-15 01:12:51 +02:00
Simon Sessingø e5c86c1822 Merge pull request #129 from skipperbent/v2-development
Bugfixes
2016-11-15 01:12:41 +02:00
Simon Sessingø 973344e46e Merge pull request #128 from skipperbent/v2
V2
2016-11-08 18:23:22 +02:00
Simon Sessingø 32c305bd2c Merge pull request #124 from skipperbent/v2-development
V2 development
2016-11-08 18:22:49 +02:00
Simon Sessingø 4a03005c68 Merge pull request #122 from skipperbent/development
Fixed urls in groups not working
2016-11-06 09:04:56 +01:00
Simon Sessingø 52034411cf Merge pull request #121 from skipperbent/development
Development
2016-11-06 08:14:36 +01:00
Simon Sessingø 4c8ed5bb3d Merge pull request #120 from skipperbent/development
Development
2016-11-05 23:09:19 +01:00
Simon Sessingø 9fed6ffb3f Merge pull request #119 from skipperbent/development
Optimised for cli-usage
2016-10-28 07:41:21 +02:00
Simon Sessingø 15da599e82 Merge pull request #118 from skipperbent/development
Minor optimisations
2016-10-27 19:15:59 +02:00
Simon Sessingø 9274acb591 Merge pull request #117 from skipperbent/development
Optimisations and bugfixes
2016-10-27 17:06:24 +02:00
Simon Sessingø 5c7759ab72 Merge pull request #116 from skipperbent/development
Development
2016-10-27 16:45:29 +02:00
Simon Sessingø c7b8593185 Merge pull request #114 from skipperbent/development
Development
2016-10-20 08:38:23 +02:00
Simon Sessingø fb478f475c Merge pull request #113 from skipperbent/development
Development
2016-10-20 08:35:20 +02:00
Simon Sessingø 1142d9d4ce Merge pull request #112 from skipperbent/development
Optimised middleware load order
2016-09-28 12:30:06 +02:00
Simon Sessingø 5d5c96e802 Merge pull request #111 from skipperbent/development
Automatically push middlewares if multiple in nested group.
2016-09-28 12:24:38 +02:00
Simon Sessingø bfdaf8ac52 Merge pull request #110 from skipperbent/development
Updated documentation and added demo-project.
2016-09-26 14:39:50 +02:00
Simon Sessingø 71dc6e172f Merge pull request #108 from skipperbent/development
Allow for default parameters (including A-Z, a-z, 0-9 and "-") when p…
2016-06-14 22:21:20 +02:00
Simon Sessingø 6ee172927f Merge pull request #107 from skipperbent/development
Bugfix
2016-06-04 18:44:59 +02:00
Simon Sessingø bb5e629199 Merge pull request #106 from skipperbent/development
Development
2016-06-04 18:21:16 +02:00
Simon Sessingø 0cc0a59fd5 Merge pull request #105 from skipperbent/development
Development
2016-06-04 15:13:47 +02:00
Simon Sessingø 498fd6b07d Merge pull request #103 from skipperbent/development
Added setValue method to InputItem class.
2016-05-04 13:41:36 +02:00
Simon Sessingø 96ab22a4f8 Merge pull request #102 from skipperbent/development
Added exist method to Input class.
2016-05-03 07:21:16 +02:00
Simon Sessingø 7f528c133b Merge pull request #101 from skipperbent/development
Development
2016-05-01 02:01:47 +02:00
Simon Sessingø 5a50190293 Merge pull request #100 from skipperbent/development
Development
2016-04-25 00:41:50 +02:00
Simon Sessingø 355ef01d63 Merge pull request #99 from skipperbent/development
Development
2016-04-22 15:38:02 +02:00
Simon Sessingø d3162b5a2b Merge pull request #98 from skipperbent/development
Development
2016-04-22 14:30:40 +02:00
Simon Sessingø 810b80487d Merge pull request #97 from skipperbent/development
- Added custom ExceptionHandler example to documentation.
2016-04-21 08:30:34 +02:00
Simon Sessingø 18a9df56ca Merge pull request #96 from skipperbent/development
Development
2016-04-20 08:10:18 +02:00
Simon Sessingø 6e14ded03f Merge pull request #95 from skipperbent/development
Development
2016-04-16 23:23:56 +02:00
Simon Sessingø 899081f8d8 Merge pull request #94 from skipperbent/development
Update README.md
2016-04-16 00:01:22 +02:00
Simon Sessingø e7b9206bc9 Merge pull request #93 from skipperbent/development
Development
2016-04-15 23:21:00 +02:00
Simon Sessingø cd6e800984 Merge pull request #91 from skipperbent/development
Development
2016-04-15 23:14:55 +02:00
Simon Sessingø 11bd5a7d11 Merge pull request #89 from skipperbent/development
[BUGFIX] Fixed notice
2016-04-09 15:39:12 +02:00
Simon Sessingø be32796b01 Merge pull request #88 from skipperbent/development
[TASK] Moved group-middleware rendering to routeRequest to ensure all…
2016-04-09 15:32:45 +02:00
Simon Sessingø 8b3d71a328 Merge pull request #87 from skipperbent/development
[BUGFIX] Fixed only match group route if prefix is set
2016-04-09 10:02:22 +02:00
Simon Sessingø 1fae638aaf Merge pull request #86 from skipperbent/development
Development
2016-04-09 09:50:56 +02:00
Simon Sessingø 37c8bc9f32 Merge pull request #79 from skipperbent/development
[BUGFIX] Bugfixes and optimisations
2016-04-07 23:21:13 +02:00
Simon Sessingø 75029b330a Merge pull request #78 from skipperbent/development
[BUGFIX] Fixed nested groups not merging settings to routes
2016-04-07 19:34:02 +02:00
Simon Sessingø fd5d893040 Merge pull request #77 from skipperbent/development
[TASK] Added rewrite_uri parameter to Request class
2016-03-19 19:12:42 +01:00
Simon Sessingø c1512740af Merge pull request #76 from skipperbent/development
[BUGFIX] Readded rendering of groups
2016-03-19 18:59:01 +01:00
Simon Sessingø 212ae133de Merge pull request #75 from skipperbent/development
[TASK] Readded merging
2016-03-19 17:40:26 +01:00
Simon Sessingø ae58231fa1 Merge pull request #74 from skipperbent/development
Custom boot-managers
2016-03-19 16:29:03 +01:00
Simon Sessingø 358b25d4f1 Merge pull request #73 from skipperbent/development
Development
2016-03-18 17:55:31 +01:00
Simon Sessingø 3d45851d9b Merge pull request #72 from skipperbent/development
[BUGFIX] Only render group if prefix matches.
2016-03-16 19:58:03 +01:00
Simon Sessingø ee5c2207f8 Merge pull request #71 from skipperbent/development
Added support for x-forwarded-proto http header
2016-03-14 01:08:25 +01:00
Simon Sessingø b1ca3fc9ef Merge pull request #70 from skipperbent/development
[FEATURE] Added http code to redirect method.
2016-03-14 00:59:09 +01:00
Simon Sessingø 253c0c70d4 Merge pull request #69 from skipperbent/development
[BUGFIX] Bugfix
2016-03-01 22:52:38 +01:00
Simon Sessingø 53ba2d7ac5 Merge pull request #68 from skipperbent/development
[TASK] Fixed regex causing optional parameters to sometimes catch req…
2016-01-23 16:12:27 +01:00
Simon Sessingø 315fe05769 Merge pull request #67 from skipperbent/development
Development
2016-01-17 04:57:39 +01:00
Simon Sessingø a57113309a Merge pull request #66 from skipperbent/development
Development
2016-01-15 11:56:04 +01:00
40 changed files with 1357 additions and 446 deletions
+1 -2
View File
@@ -1,4 +1,3 @@
.idea
composer.lock
vendor/
demo-project/vendor
vendor/
+153 -36
View File
@@ -22,6 +22,7 @@ If you want a great new feature or experience any issues what-so-ever, please fe
- [Installation](#installation)
- [Setting up Apache](#setting-up-apache)
- [Setting up Nginx](#setting-up-nginx)
- [Setting up IIS](#setting-up-iis)
- [Configuration](#configuration)
- [Helper functions](#helper-functions)
@@ -34,6 +35,7 @@ If you want a great new feature or experience any issues what-so-ever, please fe
- [Optional parameters](#optional-parameters)
- [Regular expression constraints](#regular-expression-constraints)
- [Regular expression route-match](#regular-expression-route-match)
- [Custom regex for matching parameters](#custom-regex-for-matching-parameters)
- [Named routes](#named-routes)
- [Generating URLs To Named Routes](#generating-urls-to-named-routes)
- [Router groups](#router-groups)
@@ -51,8 +53,9 @@ If you want a great new feature or experience any issues what-so-ever, please fe
- [Middlewares](#middlewares)
- [Example](#example)
- [ExceptionHandler](#exceptionhandler)
- [Example](#example-1)
- [ExceptionHandlers](#exceptionhandlers)
- [Handling 404, 403 and other errors](#handling-404-403-and-other-errors)
- [Using custom exception handlers](#using-custom-exception-handlers)
- [Urls](#urls)
- [Get by name (single route)](#get-by-name-single-route)
@@ -70,12 +73,13 @@ If you want a great new feature or experience any issues what-so-ever, please fe
- [Get all parameters](#get-all-parameters)
- [Advanced](#advanced)
- [Bootmanager: loading routes dynamically](#bootmanager-loading-routes-dynamically)
- [Url rewriting](#url-rewriting)
- [Rewrite using callback](#rewrite-using-callback)
- [Rewrite using url](#rewrite-using-url)
- [Adding routes manually](#adding-routes-manually)
- [Bootmanager: loading routes dynamically](#bootmanager-loading-routes-dynamically)
- [Adding routes manually](#adding-routes-manually)
- [Parameters](#parameters)
- [Custom default regex for matching parameters](#custom-default-regex-for-matching-parameters)
- [Extending](#extending)
- [Credits](#credits)
@@ -155,6 +159,59 @@ location / {
Nothing special is required for Apache to work. We've include the `.htaccess` file in the `public` folder. If rewriting is not working for you, please check that the `mod_rewrite` module (htaccess support) is enabled in the Apache configuration.
#### .htaccess example
Below is an example of an working `.htaccess` file used by simple-php-router.
Simply create a new `.htaccess` file in your projects `public` directory and paste the contents below in your newly created file. This will redirect all requests to your `index.php` file (see Configuration section below).
```
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(.*)$ index.php/$1
```
### Setting up IIS
On IIS you have to add some lines your `web.config` file in the `public` folder or create a new one. If rewriting is not working for you, please check that your IIS version have included the `url rewrite` module or download and install them from Microsoft web site.
#### web.config example
Below is an example of an working `web.config` file used by simple-php-router.
Simply create a new `web.config` file in your projects `public` directory and paste the contents below in your newly created file. This will redirect all requests to your `index.php` file (see Configuration section below). If the `web.config` file already exists, add the `<rewrite>` section inside the `<system.webServer>` branch.
```
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<!-- Remove slash '/' from the en of the url -->
<rule name="RewriteRequestsToPublic">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<action type="Rewrite" url="/{R:0}" />
</rule>
<!-- When requested file or folder don't exists, will request again through index.php -->
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/index.php/{R:1}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
```
### Configuration
Create a new file, name it `routes.php` and place it in your library folder. This will be the file where you define all the routes for your project.
@@ -187,9 +244,9 @@ SimpleRouter::start();
### Helper functions
We recommend that you add these helper functions to your project. Theese will allow you to access functionality of the router more easily.
We recommend that you add these helper functions to your project. These will allow you to access functionality of the router more easily.
To implement the functions below, simply copy the code to a new file and require the file before initializing the router.
To implement the functions below, simply copy the code to a new file and require the file before initializing the router or copy the `helpers.php` we've included in this library.
```php
<?php
@@ -233,10 +290,18 @@ function request()
/**
* Get input class
* @return \Pecee\Http\Input\Input
* @param string|null $index Parameter index name
* @param string|null $defaultValue Default return value
* @param string|array|null $methods Default method
* @return \Pecee\Http\Input\Input|string
*/
function input()
function input($index = null, $defaultValue = null, $methods = null)
{
if($index !== null)
{
return request()->getInput()->get($index, $defaultValue, $methods);
}
return request()->getInput();
}
@@ -365,7 +430,7 @@ The example below is using the following regular expression: `/ajax/([\w]+)/?([0
**Matches:** `/ajax/abc/`, `/ajax/abc/123/`
**Doesn't match:** `/ajax/`
**Won't match:** `/ajax/`
Match groups specified in the regex will be passed on as parameters:
@@ -376,13 +441,42 @@ SimpleRouter::all('/ajax/abc/123', function($param1, $param2) {
})->setMatch('/\/ajax\/([\w]+)\/?([0-9]+)?\/?/is');
```
### Custom regex for matching parameters
By default simple-php-router uses the `\w` regular expression when matching parameters.
This decision was made with speed and reliability in mind, as this match will match both letters, number and most of the used symbols on the internet.
However, sometimes it can be necessary to add a custom regular expression to match more advanced characters like `-` etc.
Instead of adding a custom regular expression to all your parameters, you can simply add a global regular expression which will be used on all the parameters on the route.
**Note:** If you the regular expression to be available across, we recommend using the global parameter on a group as demonstrated in the examples below.
#### Example
This example will ensure that all parameters use the `[\w\-]+` regular expression when parsing.
```php
SimpleRouter::get('/path/{parameter}', 'VideoController@home', ['defaultParameterRegex' => '[\w\-]+']);
```
You can also apply this setting to a group if you need multiple routes to use your custom regular expression when parsing parameters.
```php
SimpleRouter::group(['defaultParameterRegex' => '[\w\-]+'], function() {
SimpleRouter::get('/path/{parameter}', 'VideoController@home');
});
```
## Named routes
Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the name method onto the route definition:
```php
SimpleRouter::get('/user/profile', function () {
//
// Your code here
})->name('profile');
```
@@ -611,13 +705,30 @@ class CustomMiddleware implements Middleware {
---
# ExceptionHandler
# ExceptionHandlers
ExceptionHandler are classes that handles all exceptions. ExceptionsHandlers must implement the `IExceptionHandler` interface.
## Example
## Handling 404, 403 and other errors
Resource controllers can implement the `IRestController` interface, but is not required.
If you simply want to catch a 404 (page not found) etc. you can use the `Router::error($callback)` static helper method.
This will add a callback method which is fired whenever an error occurs on all routes.
The basic example below simply redirect the page to `/not-found` if an `NotFoundHttpException` (404) occurred.
The code should be placed in the file that contains your routes.
```php
Router::get('/not-found', 'PageController@notFound');
Router::error(function(Request $request, \Exception $exception) {
if($exception instanceof NotFoundHttpException && $exception->getCode() == 404) {
response()->redirect('/not-found');
}
});
```
## Using custom exception handlers
This is a basic example of an ExceptionHandler implementation (please see "[Easily overwrite route about to be loaded](#easily-overwrite-route-about-to-be-loaded)" for examples on how to change callback).
@@ -635,7 +746,7 @@ class CustomExceptionHandler implements IExceptionHandler
/* You can use the exception handler to format errors depending on the request and type. */
if (stripos($request->getUri(), '/api') !== false) {
if (stripos($request->getUri()->getPath(), '/api') !== false) {
response()->json([
'error' => $error->getMessage(),
@@ -762,7 +873,7 @@ If items is grouped in the html, it will return an array of items.
**Note:** `get` will automatically trim the value and ensure that it's not empty. If it's empty the `$defaultValue` will be returned.
```php
$value = input()->get($index, $defaultValue, $methods);
$value = input($index, $defaultValue, $methods);
```
### Get parameter object
@@ -771,11 +882,11 @@ Will return an instance of `InputItem` or `InputFile` depending on the type.
You can use this in your html as it will render the value of the item.
However if you want to compare value in your if statements, you have to use
the `getValue` or use the `input()->get()` instead.
the `getValue` or use the `input()` instead.
If items is grouped in the html, it will return an array of items.
**Note:** `getObject` will only return `$defaultValue` if the item doesn't exist. If you want `$defaultValue` to be returned if the item is empty, please use `input()->get()` instead.
**Note:** `getObject` will only return `$defaultValue` if the item doesn't exist. If you want `$defaultValue` to be returned if the item is empty, please use `input()` instead.
```php
$object = input()->getObject($index, $defaultValue = null, $methods = null);
@@ -792,13 +903,17 @@ $object = input()->getObject($index, $defaultValue = null, $methods = null);
* $defaultValue is returned if the value is empty.
*/
$id = input()->get($index, $defaultValue);
$id = input()->get($index, $defaultValue, $method);
# -- shortcut to above --
$id = input($index, $defaultValue, $method);
# -- match specific --
$object = input()->get($index, $defaultValue, 'get');
$object = input()->get($index, $defaultValue, 'post');
$object = input()->get($index, $defaultValue, 'file');
$object = input($index, $defaultValue, 'get');
$object = input($index, $defaultValue, 'post');
$object = input($index, $defaultValue, 'file');
# -- or --
@@ -817,7 +932,7 @@ $object = input()->findFile($index, $defaultValue);
*/
/* @var $image \Pecee\Http\Input\InputFile */
foreach(input()->get('images', []) as $image)
foreach(input('images', []) as $image)
{
if($image->getMime() === 'image/jpeg') {
@@ -863,7 +978,7 @@ Below example requires you to have the helper functions added. Please refer to t
```php
/* Get parameter site_id or default-value 2 from either post-value or query-string */
$siteId = input()->get('site_id', 2, ['post', 'get']);
$siteId = input('site_id', 2, ['post', 'get']);
```
---
@@ -888,11 +1003,9 @@ $request->setRewriteCallback('Example\MyCustomClass@hello');
$request->setRewriteUrl('/my-rewrite-url');
```
### Examples
**Note:** It's only possible to change the route BEFORE the route has initially been rendered. You can use the `Request` object to manipulate the route which are about to be loaded.
It's only possible to change the route BEFORE the route has initially been rendered. You can use the `Request` object to manipulate the route which are about to be loaded.
#### Rewrite using callback
### Rewrite using callback
This method is most efficient, as it will render the route immediately.
@@ -908,7 +1021,7 @@ The example below will render `DefaultController@notFound` regardless of the url
**NOTE: Use this method if you want to load another controller. No additional middlewares or rules will be loaded.**
#### Middleware example
##### Middleware example
```php
namespace Demo\Middlewares;
@@ -928,7 +1041,7 @@ class CustomMiddleware implements IMiddleware {
}
```
#### Exception handler example
##### Exception handler example
```php
namespace Demo\Handlers;
@@ -963,7 +1076,7 @@ class CustomExceptionHandler implements IExceptionHandler
}
```
#### Rewrite using url
### Rewrite using url
The example below will cause the router to reload the request and reinitialize all the routes. This method is slower, but will ensure that all middlewares and rules for the route is loaded.
@@ -974,7 +1087,7 @@ We are using the `url()` helper function to get the uri to another route added i
**NOTE: Use this method if you want to fully load another route using it's settings (request method, middlewares etc).**
#### Middleware example
##### Middleware example
The example below will redirect the request to the `home`-route.
@@ -995,7 +1108,7 @@ class CustomMiddleware implements IMiddleware {
}
```
# Bootmanager: loading routes dynamically
### Bootmanager: loading routes dynamically
Sometimes it can be necessary to keep urls stored in the database, file or similar. In this example, we want the url ```/my-cat-is-beatiful``` to load the route ```/article/view/1``` which the router knows, because it's defined in the ```routes.php``` file.
@@ -1018,7 +1131,7 @@ class CustomRouterRules implement IRouterBootManager {
// If the current uri matches the url, we use our custom route
if($request->getUri() === $url) {
if($request->getUri()->getPath() === $url) {
$request->setRewriteUrl($rule);
return $request;
}
@@ -1041,7 +1154,7 @@ The last thing we need to do, is to add our custom boot-manager to the ```routes
SimpleRouter::addBootManager(new CustomRouterRules());
```
## Adding routes manually
### Adding routes manually
The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```Router``` class.
If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you.
@@ -1059,7 +1172,7 @@ $route = new RouteUrl('/answer/1', function() {
});
$route->setMiddleware(\Demo\Middlewares\AuthMiddleware::class);
$route->addMiddleware(\Demo\Middlewares\AuthMiddleware::class);
$route->setNamespace('\Demo\Controllers');
$route->setPrefix('v1');
@@ -1067,6 +1180,10 @@ $route->setPrefix('v1');
$router->addRoute($route);
```
## Parameters
This section contains advanced tips & tricks on extending the usage for parameters.
## Extending
This is a simple example of an integration into a framework.
+4 -1
View File
@@ -2,11 +2,14 @@
"name": "pecee/simple-router",
"description": "Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.",
"keywords": [
"router",
"router",
"routing",
"route",
"simple-php-router",
"laravel",
"pecee",
"route"
"php"
],
"license": "MIT",
"support": {
+66
View File
@@ -0,0 +1,66 @@
<?php
use Pecee\SimpleRouter\SimpleRouter as Router;
/**
* Get url for a route by using either name/alias, class or method name.
*
* The name parameter supports the following values:
* - Route name
* - Controller/resource name (with or without method)
* - Controller class name
*
* When searching for controller/resource by name, you can use this syntax "route.name@method".
* You can also use the same syntax when searching for a specific controller-class "MyController@home".
* If no arguments is specified, it will return the url for the current loaded route.
*
* @param string|null $name
* @param string|array|null $parameters
* @param array|null $getParams
* @return string
*/
function url($name = null, $parameters = null, $getParams = null)
{
return Router::getUrl($name, $parameters, $getParams);
}
/**
* @return \Pecee\Http\Response
*/
function response()
{
return Router::response();
}
/**
* @return \Pecee\Http\Request
*/
function request()
{
return Router::request();
}
/**
* Get input class
* @param string|null $index Parameter index name
* @param string|null $defaultValue Default return value
* @param string|array|null $methods Default method
* @return \Pecee\Http\Input\Input|string
*/
function input($index = null, $defaultValue = null, $methods = null)
{
if ($index !== null) {
return request()->getInput()->get($index, $defaultValue, $methods);
}
return request()->getInput();
}
function redirect($url, $code = null)
{
if ($code !== null) {
response()->httpCode($code);
}
response()->redirect($url);
}
@@ -1,7 +1,7 @@
<?php
namespace Pecee\Controllers;
interface IRestController
interface IResourceController
{
/**
+11 -3
View File
@@ -3,13 +3,14 @@ namespace Pecee;
class CsrfToken
{
const CSRF_KEY = 'XSRF-TOKEN';
const CSRF_KEY = 'CSRF-TOKEN';
protected $token;
/**
* Generate random identifier for CSRF token
*
* @throws \RuntimeException
* @return string
*/
public static function generateToken()
@@ -18,7 +19,14 @@ class CsrfToken
return bin2hex(random_bytes(32));
}
return bin2hex(openssl_random_pseudo_bytes(32));
$isSourceStrong = false;
$random = openssl_random_pseudo_bytes(32, $isSourceStrong);
if ($isSourceStrong === false || $random === false) {
throw new \RuntimeException('IV generation failed');
}
return $random;
}
/**
@@ -52,7 +60,7 @@ class CsrfToken
*/
public function getToken()
{
if ($this->hasToken()) {
if ($this->hasToken() === true) {
return $_COOKIE[static::CSRF_KEY];
}
@@ -0,0 +1,38 @@
<?php
namespace Pecee\Handlers;
use Pecee\Http\Request;
/**
* Class CallbackExceptionHandler
*
* Class is used to create callbacks which are fired when an exception is reached.
* This allows for easy handling 404-exception etc. without creating an custom ExceptionHandler.
*
* @package Pecee\Handlers
*/
class CallbackExceptionHandler implements IExceptionHandler
{
protected $callback;
public function __construct(\Closure $callback)
{
$this->callback = $callback;
}
/**
* @param Request $request
* @param \Exception $error
* @return Request|null
*/
public function handleError(Request $request, \Exception $error)
{
/* Fire exceptions */
return call_user_func($this->callback,
$request,
$error
);
}
}
+3 -11
View File
@@ -60,7 +60,7 @@ class Input
{
$list = [];
foreach ($_FILES as $key => $value) {
foreach ((array)$_FILES as $key => $value) {
// Handle array input
if (is_array($value['name']) === false) {
@@ -108,11 +108,11 @@ class Input
$file = InputFile::createFromArray([
'index' => $key,
'filename' => $getItem($key),
'error' => $getItem($key, 'error'),
'tmp_name' => $getItem($key, 'tmp_name'),
'type' => $getItem($key, 'type'),
'size' => $getItem($key, 'size'),
'filename' => $getItem($key, 'name'),
]);
if (isset($output[$key])) {
@@ -283,15 +283,7 @@ class Input
}
}
$output = array_merge($_GET, $output);
if ($filter !== null) {
$output = array_filter($output, function ($key) use ($filter) {
return (in_array($key, $filter) === true);
}, ARRAY_FILTER_USE_KEY);
}
return $output;
return ($filter !== null) ? array_intersect_key($output, array_flip($filter)) : array_merge($_GET, $output);
}
}
@@ -41,9 +41,9 @@ class BaseCsrfVerifier implements IMiddleware
$url = rtrim($url, '/');
if ($url[strlen($url) - 1] === '*') {
$url = rtrim($url, '*');
$skip = (stripos($request->getUri(), $url) === 0);
$skip = (stripos($request->getUri()->getPath(), $url) === 0);
} else {
$skip = ($url === rtrim($request->getUri(), '/'));
$skip = ($url === $request->getUri()->getPath());
}
if ($skip === true) {
+10 -7
View File
@@ -8,7 +8,7 @@ use Pecee\SimpleRouter\SimpleRouter;
class Request
{
protected $data = [];
private $data = [];
protected $headers;
protected $host;
protected $uri;
@@ -29,8 +29,11 @@ class Request
public function __construct()
{
$this->parseHeaders();
$this->host = $this->getHeader('http-host');
$this->uri = $this->getHeader('request-uri');
$this->setHost($this->getHeader('http-host'));
// Check if special IIS header exist, otherwise use default.
$this->setUri(new Uri($this->getHeader('unencoded-url', $this->getHeader('request-uri'))));
$this->input = new Input($this);
$this->method = strtolower($this->input->get('_method', $this->getHeader('request-method'), 'post'));
}
@@ -58,7 +61,7 @@ class Request
}
/**
* @return string
* @return Uri
*/
public function getUri()
{
@@ -164,7 +167,7 @@ class Request
*/
public function getHeader($name, $defaultValue = null)
{
if (isset($this->headers[strtolower($name)])) {
if (array_key_exists(strtolower($name), $this->headers) === true) {
return $this->headers[strtolower($name)];
}
@@ -215,9 +218,9 @@ class Request
}
/**
* @param string $uri
* @param Uri $uri
*/
public function setUri($uri)
public function setUri(Uri $uri)
{
$this->uri = $uri;
}
+12 -6
View File
@@ -1,4 +1,5 @@
<?php
namespace Pecee\Http;
class Response
@@ -41,7 +42,7 @@ class Response
public function refresh()
{
$this->redirect($this->request->getUri());
$this->redirect($this->request->getUri()->getPath());
}
/**
@@ -82,14 +83,19 @@ class Response
}
/**
* Json encode array
* @param array $value
* Json encode
* @param array|\JsonSerializable $value
* @throws \InvalidArgumentException;
*/
public function json(array $value)
public function json($value)
{
$this->header('Content-Type: application/json');
if (($value instanceof \JsonSerializable) === false && is_array($value) === false) {
throw new \InvalidArgumentException('Invalid type for parameter "value". Must be of type array or object implementing the \JsonSerializable interface.');
}
$this->header('Content-type: application/json');
echo json_encode($value);
die();
exit(0);
}
/**
+172
View File
@@ -0,0 +1,172 @@
<?php
namespace Pecee\Http;
class Uri
{
private $originalUrl;
private $data = [
'scheme',
'host',
'port',
'user',
'pass',
'path',
'query',
'fragment',
];
public function __construct($url)
{
$this->originalUrl = $url;
$this->data = array_merge($this->data, $this->parseUrl(urldecode($url)));
if (isset($this->data['path']) === true && $this->data['path'] !== '/') {
$this->data['path'] = rtrim($this->data['path'], '/') . '/';
}
}
/**
* Check if url is using a secure protocol like https
* @return bool
*/
public function isSecure()
{
return (strtolower($this->getScheme()) === 'https');
}
/**
* Checks if url is relative
* @return bool
*/
public function isRelative()
{
return ($this->getHost() === null);
}
/**
* Get url scheme
* @return string|null
*/
public function getScheme()
{
return $this->data['scheme'];
}
/**
* Get url host
* @return string|null
*/
public function getHost()
{
return $this->data['host'];
}
/**
* Get url port
* @return int|null
*/
public function getPort()
{
return ($this->data['port'] !== null) ? (int)$this->data['port'] : null;
}
/**
* Parse username from url
* @return string|null
*/
public function getUserName()
{
return $this->data['user'];
}
/**
* Parse password from url
* @return string|null
*/
public function getPassword()
{
return $this->data['pass'];
}
/**
* Get path from url
* @return string
*/
public function getPath()
{
return $this->data['path'];
}
/**
* Get querystring from url
* @return string|null
*/
public function getQueryString()
{
return $this->data['query'];
}
/**
* Get fragment from url (everything after #)
* @return string|null
*/
public function getFragment()
{
return $this->data['fragment'];
}
/**
* @return string
*/
public function getOriginalUrl()
{
return $this->originalUrl;
}
/**
* UTF-8 aware parse_url() replacement.
* @param string $url
* @param int $component
* @throws \InvalidArgumentException
* @return array
*/
public function parseUrl($url, $component = -1)
{
$encodedUrl = preg_replace_callback(
'%[^:/@?&=#]+%u',
function ($matches) {
return urlencode($matches[0]);
},
$url
);
$parts = parse_url($encodedUrl, $component);
if ($parts === false) {
throw new \InvalidArgumentException('Malformed URL: ' . $url);
}
foreach ((array)$parts as $name => $value) {
$parts[$name] = urldecode($value);
}
return $parts;
}
/**
* Returns data array with information about the url
* @return array
*/
public function getData()
{
return $this->data;
}
public function __toString()
{
return $this->getOriginalUrl();
}
}
@@ -1,6 +1,8 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Handlers\IExceptionHandler;
use Pecee\Http\Request;
interface IGroupRoute extends IRoute
@@ -13,6 +15,14 @@ interface IGroupRoute extends IRoute
*/
public function matchDomain(Request $request);
/**
* Add exception handler
*
* @param IExceptionHandler|string $handler
* @return static $this;
*/
public function addExceptionHandler($handler);
/**
* Set exception-handlers for group
*
+2 -1
View File
@@ -1,4 +1,5 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Request;
@@ -173,7 +174,7 @@ interface IRoute
* @param string $middleware
* @return static
*/
public function setMiddleware($middleware);
public function addMiddleware($middleware);
/**
* Set middlewares array
+24 -22
View File
@@ -1,4 +1,5 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Middleware\IMiddleware;
@@ -35,10 +36,12 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
$middleware = $this->getMiddlewares()[$i];
$middleware = $this->loadClass($middleware);
if (is_object($middleware) === false) {
$middleware = $this->loadClass($middleware);
}
if (($middleware instanceof IMiddleware) === false) {
throw new HttpException($middleware . ' must be instance of Middleware');
throw new HttpException($middleware . ' must be inherit the IMiddleware interface');
}
$middleware->handle($request);
@@ -54,17 +57,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
return null;
}
$parameters = [];
if (preg_match($this->regex, $request->getHost() . $url, $parameters) > 0) {
/* Remove global match */
$this->parameters = array_slice($parameters, 1);
return true;
}
return false;
return (preg_match($this->regex, $request->getHost() . $url) > 0);
}
/**
@@ -79,9 +72,9 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
if (strpos($this->url, $this->paramModifiers[0]) !== false) {
$regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
if (preg_match_all('/' . $regex . '/', $this->url, $matches)) {
if (preg_match_all('/' . $regex . '/u', $this->url, $matches)) {
$this->parameters = array_fill_keys($matches[1], null);
}
}
@@ -99,7 +92,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
* Used when calling the url() helper.
*
* @param string|null $method
* @param array|null $parameters
* @param string|array|null $parameters
* @param string|null $name
* @return string
*/
@@ -107,8 +100,10 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
{
$url = $this->getUrl();
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
$url = '//' . $this->getGroup()->getDomains()[0] . $url;
$group = $this->getGroup();
if ($group !== null && count($group->getDomains()) > 0) {
$url = '//' . $group->getDomains()[0] . $url;
}
/* Contains parameters that aren't recognized and will be appended at the end of the url */
@@ -128,11 +123,17 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
for ($i = $max; $i >= 0; $i--) {
$param = $keys[$i];
$value = $value = ($parameters !== null && array_key_exists($param, $parameters)) ? $parameters[$param] : $params[$param];
/* If parameter is specifically set to null - use the original-defined value */
if ($value === null && isset($this->originalParameters[$param])) {
$value = $this->originalParameters[$param];
if ($parameters === '' || (is_array($parameters) && count($parameters) === 0)) {
$value = '';
} else {
$p = (array)$parameters;
$value = array_key_exists($param, $p) ? $p[$param] : $params[$param];
/* If parameter is specifically set to null - use the original-defined value */
if ($value === null && isset($this->originalParameters[$param])) {
$value = $this->originalParameters[$param];
}
}
if (stripos($url, $param1) !== false || stripos($url, $param) !== false) {
@@ -143,6 +144,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
}
}
$url = '/' . ltrim($url, '/');
$url .= join('/', $unknownParams);
return rtrim($url, '/') . '/';
+118 -43
View File
@@ -1,12 +1,15 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
abstract class Route implements IRoute
{
const PARAMETERS_REGEX_MATCH = '%s([\w]+)(\%s?)%s';
const PARAMETERS_REGEX_FORMAT = '%s([\w]+)(\%s?)%s';
const PARAMETERS_DEFAULT_REGEX = '[\w]+';
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_POST = 'post';
@@ -31,6 +34,12 @@ abstract class Route implements IRoute
* @var bool
*/
protected $filterEmptyParams = false;
/**
* Default regular expression used for parsing parameters.
* @var string|null
*/
protected $defaultParameterRegex;
protected $paramModifiers = '{}';
protected $paramOptionalSymbol = '?';
protected $group;
@@ -49,7 +58,7 @@ abstract class Route implements IRoute
protected function loadClass($name)
{
if (class_exists($name) === false) {
throw new NotFoundHttpException(sprintf('Class %s does not exist', $name), 404);
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $name), 404);
}
return new $name();
@@ -59,48 +68,55 @@ abstract class Route implements IRoute
{
$callback = $this->getCallback();
if ($callback !== null && is_callable($callback)) {
if ($callback === null) {
return;
}
/* Render callback function */
if (is_callable($callback) === true) {
/* When the callback is a function */
call_user_func_array($callback, $this->getParameters());
return call_user_func_array($callback, $this->getParameters());
} else {
/* When the callback is a method */
$controller = explode('@', $callback);
$namespace = $this->getNamespace();
$className = ($namespace !== null && $controller[0][0] !== '\\') ? $namespace . '\\' . $controller[0] : $controller[0];
$class = $this->loadClass($className);
$method = $controller[1];
if (method_exists($class, $method) === false) {
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}
$parameters = $this->getParameters();
/* Filter parameters with null-value */
if ($this->filterEmptyParams === true) {
$parameters = array_filter($parameters, function ($var) {
return ($var !== null);
});
}
call_user_func_array([$class, $method], $parameters);
}
/* When the callback is a class + method */
$controller = explode('@', $callback);
$namespace = $this->getNamespace();
$className = ($namespace !== null && $controller[0][0] !== '\\') ? $namespace . '\\' . $controller[0] : $controller[0];
$class = $this->loadClass($className);
$method = $controller[1];
if (method_exists($class, $method) === false) {
throw new NotFoundHttpException(sprintf('Method "%s" does not exist in class "%s"', $method, $className), 404);
}
$parameters = $this->getParameters();
/* Filter parameters with null-value */
if ($this->filterEmptyParams === true) {
$parameters = array_filter($parameters, function ($var) {
return ($var !== null);
});
}
return call_user_func_array([$class, $method], $parameters);
}
protected function parseParameters($route, $url, $parameterRegex = '[\w]+')
protected function parseParameters($route, $url, $parameterRegex = null)
{
$regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
$parameters = [];
if (preg_match_all('/' . $regex . '/', $route, $parameters)) {
// Ensures that hostnames/domains will work with parameters
$url = '/' . ltrim($url, '/');
if (preg_match_all('/' . $regex . '/u', $route, $parameters)) {
$urlParts = preg_split('/((\-?\/?)\{[^}]+\})/', rtrim($route, '/'));
@@ -111,8 +127,21 @@ abstract class Route implements IRoute
if ($key < count($parameters[1])) {
$name = $parameters[1][$key];
$regex = isset($this->where[$name]) ? $this->where[$name] : $parameterRegex;
$regex = sprintf('\-?\/?(?P<%s>%s)', $name, $regex) . $parameters[2][$key];
/* If custom regex is defined, use that */
if (isset($this->where[$name]) === true) {
$regex = $this->where[$name];
} else {
/* If method specific regex is defined use that, otherwise use the default parameter regex */
if ($parameterRegex !== null) {
$regex = $parameterRegex;
} else {
$regex = ($this->defaultParameterRegex === null) ? static::PARAMETERS_DEFAULT_REGEX : $this->defaultParameterRegex;
}
}
$regex = sprintf('(?:\/|\-)%1$s(?P<%2$s>%3$s)%1$s', $parameters[2][$key], $name, $regex);
}
@@ -125,11 +154,11 @@ abstract class Route implements IRoute
$urlRegex = preg_quote($route, '/');
}
if (preg_match('/^' . $urlRegex . '(\/?)$/', $url, $matches) > 0) {
if (preg_match('/^' . $urlRegex . '\/?$/u', $url, $matches) > 0) {
$values = [];
if (isset($parameters[1])) {
if (isset($parameters[1]) === true) {
/* Only take matched parameters with name */
foreach ($parameters[1] as $name) {
@@ -152,7 +181,7 @@ abstract class Route implements IRoute
*/
public function getIdentifier()
{
if (strpos($this->callback, '@') !== false) {
if (is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
return $this->callback;
}
@@ -249,7 +278,7 @@ abstract class Route implements IRoute
public function getMethod()
{
if (strpos($this->callback, '@') !== false) {
if (is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
$tmp = explode('@', $this->callback);
return $tmp[1];
@@ -260,7 +289,7 @@ abstract class Route implements IRoute
public function getClass()
{
if (strpos($this->callback, '@') !== false) {
if (is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
$tmp = explode('@', $this->callback);
return $tmp[0];
@@ -343,6 +372,10 @@ abstract class Route implements IRoute
$values['middleware'] = $this->middlewares;
}
if ($this->defaultParameterRegex !== null) {
$values['defaultParameterRegex'] = $this->defaultParameterRegex;
}
return $values;
}
@@ -376,6 +409,10 @@ abstract class Route implements IRoute
$this->setMiddlewares(array_merge((array)$values['middleware'], $this->middlewares));
}
if (isset($values['defaultParameterRegex'])) {
$this->setDefaultParameterRegex($values['defaultParameterRegex']);
}
return $this;
}
@@ -454,9 +491,10 @@ abstract class Route implements IRoute
}
/**
* Set middleware class-name
* Add middleware class-name
*
* @param string $middleware
* @deprecated This method is deprecated and will be removed in the near future.
* @param IMiddleware|string $middleware
* @return static
*/
public function setMiddleware($middleware)
@@ -466,6 +504,19 @@ abstract class Route implements IRoute
return $this;
}
/**
* Add middleware class-name
*
* @param IMiddleware|string $middleware
* @return static
*/
public function addMiddleware($middleware)
{
$this->middlewares[] = $middleware;
return $this;
}
/**
* Set middlewares array
*
@@ -487,4 +538,28 @@ abstract class Route implements IRoute
return $this->middlewares;
}
/**
* Set default regular expression used when matching parameters.
* This is used when no custom parameter regex is found.
*
* @param string $regex
* @return static $this
*/
public function setDefaultParameterRegex($regex)
{
$this->defaultParameterRegex = $regex;
return $this;
}
/**
* Get default regular expression used when matching parameters.
*
* @return string
*/
public function getDefaultParameterRegex()
{
return $this->defaultParameterRegex;
}
}
@@ -53,7 +53,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
if (strpos($name, '.') !== false) {
$found = array_search(substr($name, strrpos($name, '.') + 1), $this->names, false);
if ($found !== false) {
$method = $found;
$method = (string)$found;
}
}
@@ -66,7 +66,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
foreach (static::$requestTypes as $requestType) {
if (stripos($method, $requestType) === 0) {
$method = substr($method, strlen($requestType));
$method = (string)substr($method, strlen($requestType));
break;
}
}
@@ -74,8 +74,10 @@ class RouteController extends LoadableRoute implements IControllerRoute
$method .= '/';
}
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
$url .= '//' . $this->getGroup()->getDomains()[0];
$group = $this->getGroup();
if ($group !== null && count($group->getDomains()) > 0) {
$url .= '//' . $group->getDomains()[0];
}
$url .= '/' . trim($this->getUrl(), '/') . '/' . strtolower($method) . join('/', $parameters);
@@ -85,13 +87,10 @@ class RouteController extends LoadableRoute implements IControllerRoute
public function matchRoute($url, Request $request)
{
$url = parse_url(urldecode($url), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
if ($regexMatch === false || stripos($url, $this->url) !== 0 || strtolower($url) !== strtolower($this->url)) {
if ($regexMatch === false || (stripos($url, $this->url) !== 0 && strtolower($url) !== strtolower($this->url))) {
return false;
}
+16 -1
View File
@@ -1,6 +1,8 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Handlers\IExceptionHandler;
use Pecee\Http\Request;
class RouteGroup extends Route implements IGroupRoute
@@ -18,7 +20,7 @@ class RouteGroup extends Route implements IGroupRoute
*/
public function matchDomain(Request $request)
{
if (count($this->domains) === 0) {
if ($this->domains === null || count($this->domains) === 0) {
return true;
}
@@ -54,6 +56,19 @@ class RouteGroup extends Route implements IGroupRoute
return $this->matchDomain($request);
}
/**
* Add exception handler
*
* @param IExceptionHandler|string $handler
* @return static $this
*/
public function addExceptionHandler($handler)
{
$this->exceptionHandlers[] = $handler;
return $this;
}
/**
* Set exception-handlers for group
*
+16 -14
View File
@@ -1,4 +1,5 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Request;
@@ -53,7 +54,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
/* Remove method/type */
if (strpos($name, '.') !== false) {
$name = substr($name, 0, strrpos($name, '.'));
$name = (string)substr($name, 0, strrpos($name, '.'));
}
return (strtolower($this->name) === strtolower($name));
@@ -78,47 +79,48 @@ class RouteResource extends LoadableRoute implements IControllerRoute
public function matchRoute($url, Request $request)
{
$url = parse_url(urldecode($url), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
if ($regexMatch === false || stripos($url, $this->url) !== 0 || strtolower($url) !== strtolower($this->url)) {
if ($regexMatch === false || (stripos($url, $this->url) !== 0 && strtolower($url) !== strtolower($this->url))) {
return false;
}
$route = rtrim($this->url, '/') . '/{id?}/{action?}';
$parameters = $this->parseParameters($route, $url);
if ($parameters === null) {
/* Parse parameters from current route */
$this->parameters = $this->parseParameters($route, $url);
/* If no custom regular expression or parameters was found on this route, we stop */
if ($regexMatch === null && $this->parameters === null) {
return false;
}
$this->parameters = (array)$parameters;
$action = strtolower(trim($this->parameters['action']));
$id = $this->parameters['id'];
$action = isset($this->parameters['action']) ? $this->parameters['action'] : null;
// Remove action parameter
unset($this->parameters['action']);
$method = $request->getMethod();
// Delete
if ($method === static::REQUEST_TYPE_DELETE && isset($this->parameters['id'])) {
if ($method === static::REQUEST_TYPE_DELETE && $id !== null) {
return $this->call($this->methodNames['destroy']);
}
// Update
if (isset($this->parameters['id']) && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT], false)) {
if ($id !== null && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT], false) === true) {
return $this->call($this->methodNames['update']);
}
// Edit
if ($method === static::REQUEST_TYPE_GET && isset($this->parameters['id']) && strtolower($action) === 'edit') {
if ($method === static::REQUEST_TYPE_GET && $id !== null && $action === 'edit') {
return $this->call($this->methodNames['edit']);
}
// Create
if ($method === static::REQUEST_TYPE_GET && strtolower($action) === 'create') {
if ($method === static::REQUEST_TYPE_GET && $id === 'create') {
return $this->call($this->methodNames['create']);
}
@@ -128,7 +130,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
}
// Show
if ($method === static::REQUEST_TYPE_GET && isset($this->parameters['id'])) {
if ($method === static::REQUEST_TYPE_GET && $id !== null) {
return $this->call($this->methodNames['show']);
}
+8 -6
View File
@@ -1,4 +1,5 @@
<?php
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Request;
@@ -13,22 +14,23 @@ class RouteUrl extends LoadableRoute
public function matchRoute($url, Request $request)
{
$url = parse_url(urldecode($url), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
if ($regexMatch === false) {
return false;
}
/* Make regular expression based on route */
/* Parse parameters from current route */
$parameters = $this->parseParameters($this->url, $url);
if ($parameters === null) {
/* If no custom regular expression or parameters was found on this route, we stop */
if ($regexMatch === null && $parameters === null) {
return false;
}
$this->setParameters($parameters);
/* Set the parameters */
$this->setParameters((array)$parameters);
return true;
}
+58 -28
View File
@@ -1,4 +1,5 @@
<?php
namespace Pecee\SimpleRouter;
use Pecee\Handlers\IExceptionHandler;
@@ -121,7 +122,7 @@ class Router
$exceptionHandlers = [];
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
/* @var $route IRoute */
for ($i = $max; $i >= 0; $i--) {
@@ -133,20 +134,18 @@ class Router
$group = $route;
if ($route->getCallback() !== null && is_callable($route->getCallback())) {
$this->processingRoute = true;
$route->renderRoute($this->request);
$this->processingRoute = false;
$this->processingRoute = true;
$route->renderRoute($this->request);
$this->processingRoute = false;
if ($route->matchRoute($url, $this->request) === true) {
/* Add exception handlers */
if (count($route->getExceptionHandlers()) > 0) {
$exceptionHandlers += $route->getExceptionHandlers();
}
if ($route->matchRoute($url, $this->request) === true) {
/* Add exception handlers */
if (count($route->getExceptionHandlers()) > 0) {
/** @noinspection AdditionOperationOnArraysInspection */
$exceptionHandlers += $route->getExceptionHandlers();
}
}
}
@@ -183,7 +182,7 @@ class Router
}
}
$this->exceptionHandlers = array_unique(array_merge($exceptionHandlers, $this->exceptionHandlers));
$this->exceptionHandlers = array_merge($exceptionHandlers, $this->exceptionHandlers);
}
/**
@@ -225,7 +224,7 @@ class Router
}
}
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
$max = count($this->processedRoutes) - 1;
@@ -249,9 +248,8 @@ class Router
if ($rewriteRoute !== null) {
$rewriteRoute->loadMiddleware($this->request);
$rewriteRoute->renderRoute($this->request);
return;
return $rewriteRoute->renderRoute($this->request);
}
/* If the request has changed */
@@ -268,7 +266,8 @@ class Router
/* Render route */
$routeNotAllowed = false;
$this->request->setLoadedRoute($route);
$route->renderRoute($this->request);
return $route->renderRoute($this->request);
break;
}
@@ -283,13 +282,27 @@ class Router
}
if ($this->request->getLoadedRoute() === null) {
$this->handleException(new NotFoundHttpException('Route not found: ' . $this->request->getUri(), 404));
$rewriteUrl = $this->request->getRewriteUrl();
if ($rewriteUrl !== null) {
$message = sprintf('Route not found: "%s" (rewrite from: "%s")', $rewriteUrl, $this->request->getUri()->getPath());
} else {
$message = sprintf('Route not found: "%s"', $this->request->getUri()->getPath());
}
$this->handleException(new NotFoundHttpException($message, 404));
}
}
/**
* @param \Exception $e
* @throws HttpException
* @throws \Exception
*/
protected function handleException(\Exception $e)
{
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
$max = count($this->exceptionHandlers);
@@ -297,7 +310,10 @@ class Router
for ($i = 0; $i < $max; $i++) {
$handler = $this->exceptionHandlers[$i];
$handler = new $handler();
if (is_object($handler) === false) {
$handler = new $handler();
}
if (($handler instanceof IExceptionHandler) === false) {
throw new HttpException('Exception handler must implement the IExceptionHandler interface.', 500);
@@ -309,9 +325,8 @@ class Router
if ($rewriteRoute !== null) {
$rewriteRoute->loadMiddleware($this->request);
$rewriteRoute->renderRoute($this->request);
return;
return $rewriteRoute->renderRoute($this->request);
}
$rewriteUrl = $this->request->getRewriteUrl();
@@ -372,7 +387,7 @@ class Router
}
/* Using @ is most definitely a controller@method or alias@method */
if (strpos($name, '@') !== false) {
if (is_string($name) === true && strpos($name, '@') !== false) {
list($controller, $method) = array_map('strtolower', explode('@', $name));
if ($controller === strtolower($route->getClass()) && $method === strtolower($route->getMethod())) {
@@ -381,7 +396,7 @@ class Router
}
/* Check if callback matches (if it's not a function) */
if (strpos($name, '@') !== false && strpos($route->getCallback(), '@') !== false && !is_callable($route->getCallback())) {
if (is_string($name) === true && is_string($route->getCallback()) && strpos($name, '@') !== false && strpos($route->getCallback(), '@') !== false && is_callable($route->getCallback()) === false) {
/* Check if the entire callback is matching */
if (strpos($route->getCallback(), $name) === 0 || strtolower($route->getCallback()) === strtolower($name)) {
@@ -422,6 +437,10 @@ class Router
throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null');
}
if ($name === '' && $parameters === '') {
return '/';
}
/* Only merge $_GET when all parameters are null */
if ($name === null && $parameters === null && $getParams === null) {
$getParams = $_GET;
@@ -431,9 +450,7 @@ class Router
/* Return current route if no options has been specified */
if ($name === null && $parameters === null) {
$url = rtrim(parse_url($this->request->getUri(), PHP_URL_PATH), '/');
return (($url === '') ? '/' : $url . '/') . $this->arrayToParams($getParams);
return $this->request->getUri()->getPath() . $this->arrayToParams($getParams);
}
$loadedRoute = $this->request->getLoadedRoute();
@@ -451,7 +468,7 @@ class Router
}
/* Using @ is most definitely a controller@method or alias@method */
if (strpos($name, '@') !== false) {
if (is_string($name) === true && strpos($name, '@') !== false) {
list($controller, $method) = explode('@', $name);
/* Loop through all the routes to see if we can find a match */
@@ -517,6 +534,19 @@ class Router
return $this->routes;
}
/**
* Set routes
*
* @param array $routes
* @return static $this
*/
public function setRoutes(array $routes)
{
$this->routes = $routes;
return $this;
}
/**
* Get current request
*
+34 -6
View File
@@ -7,8 +7,10 @@
* This class is added so calls can be made statically like Router::get() making the code look pretty.
* It also adds some extra functionality like default-namespace.
*/
namespace Pecee\SimpleRouter;
use Pecee\Handlers\CallbackExceptionHandler;
use Pecee\Http\Middleware\BaseCsrfVerifier;
use Pecee\Http\Response;
use Pecee\SimpleRouter\Exceptions\HttpException;
@@ -33,6 +35,10 @@ class SimpleRouter
*/
protected static $response;
/**
* Router instance
* @var Router
*/
protected static $router;
/**
@@ -43,7 +49,7 @@ class SimpleRouter
*/
public static function start()
{
static::router()->routeRequest();
echo static::router()->routeRequest();
}
/**
@@ -214,7 +220,7 @@ class SimpleRouter
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouteUrl
* @return RouteUrl|IRoute
*/
public static function match(array $requestMethods, $url, $callback, array $settings = null)
{
@@ -237,7 +243,7 @@ class SimpleRouter
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouteUrl
* @return RouteUrl|IRoute
*/
public static function all($url, $callback, array $settings = null)
{
@@ -259,7 +265,7 @@ class SimpleRouter
* @param string $url
* @param string $controller
* @param array|null $settings
* @return RouteController
* @return RouteController|IRoute
*/
public static function controller($url, $controller, array $settings = null)
{
@@ -281,7 +287,7 @@ class SimpleRouter
* @param string $url
* @param string $controller
* @param array|null $settings
* @return RouteResource
* @return RouteResource|IRoute
*/
public static function resource($url, $controller, array $settings = null)
{
@@ -297,6 +303,28 @@ class SimpleRouter
return $route;
}
/**
* Add exception callback handler.
*
* @param \Closure $callback
* @return CallbackExceptionHandler $callbackHandler
*/
public static function error(\Closure $callback)
{
$routes = static::router()->getRoutes();
$callbackHandler = new CallbackExceptionHandler($callback);
$group = new RouteGroup();
$group->addExceptionHandler($callbackHandler);
array_unshift($routes, $group);
static::router()->setRoutes($routes);
return $callbackHandler;
}
/**
* Get url for a route by using either name/alias, class or method name.
*
@@ -351,7 +379,7 @@ class SimpleRouter
*/
public static function router()
{
if(static::$router === null) {
if (static::$router === null) {
static::$router = new Router();
}
+20 -10
View File
@@ -2,24 +2,34 @@
class DummyController
{
public function start()
public function method1()
{
echo static::class . '@' . 'start() OK';
}
public function method2()
{
}
public function param($params = null)
{
$params = func_get_args();
echo 'Params: ' . join(', ', $params);
echo join(', ', func_get_args());
}
public function notFound()
{
echo 'not found';
}
public function getTest()
{
echo 'getTest';
}
public function silent() {
public function postTest()
{
echo 'postTest';
}
}
public function putTest()
{
echo 'putTest';
}
}
@@ -0,0 +1,18 @@
<?php
class ResponseException extends \Exception
{
protected $response;
public function __construct($response)
{
$this->response = $response;
parent::__construct('', 0);
}
public function getResponse()
{
return $this->response;
}
}
@@ -0,0 +1,14 @@
<?php
class ExceptionHandlerFirst implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Exception $error)
{
global $stack;
$stack[] = static::class;
$request->setUri(new \Pecee\Http\Uri('/'));
return $request;
}
}
@@ -0,0 +1,14 @@
<?php
class ExceptionHandlerSecond implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Exception $error)
{
global $stack;
$stack[] = static::class;
$request->setUri(new \Pecee\Http\Uri('/'));
return $request;
}
}
@@ -0,0 +1,13 @@
<?php
class ExceptionHandlerThird implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Exception $error)
{
global $stack;
$stack[] = static::class;
throw new ResponseException('ExceptionHandler loaded');
}
}
@@ -1,13 +0,0 @@
<?php
class TestExceptionHandlerFirst implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Exception $error)
{
echo 'ExceptionHandler 1 loaded' . chr(10);
$request->setUri('/');
return $request;
}
}
@@ -1,13 +0,0 @@
<?php
class TestExceptionHandlerSecond implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Exception $error)
{
echo 'ExceptionHandler 2 loaded' . chr(10);
$request->setUri('/');
return $request;
}
}
@@ -1,12 +0,0 @@
<?php
class TestExceptionHandlerThird implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Exception $error)
{
echo 'ExceptionHandler 3 loaded' . chr(10);
throw new ExceptionHandlerException('All good!', 666);
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
class ResourceController implements \Pecee\Controllers\IResourceController
{
public function index()
{
echo 'index';
}
public function show($id)
{
echo 'show ' . $id;
}
public function store()
{
echo 'store';
}
public function create()
{
echo 'create';
}
public function edit($id)
{
echo 'edit ' . $id;
}
public function update($id)
{
echo 'update ' . $id;
}
public function destroy($id)
{
echo 'destroy ' . $id;
}
}
+26 -38
View File
@@ -2,8 +2,7 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
require_once 'Helpers/TestRouter.php';
class GroupTest extends PHPUnit_Framework_TestCase
{
@@ -13,82 +12,71 @@ class GroupTest extends PHPUnit_Framework_TestCase
{
$this->result = false;
SimpleRouter::group(['prefix' => '/group'], function () {
TestRouter::group(['prefix' => '/group'], function () {
$this->result = true;
});
try {
SimpleRouter::start();
} catch (Exception $e) {
// ignore RouteNotFound exception
}
TestRouter::debug('/', 'get');
} catch(\Exception $e) {
}
$this->assertTrue($this->result);
}
public function testNestedGroup()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/api/v1/test');
SimpleRouter::request()->setMethod('get');
TestRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/test', 'DummyController@start');
TestRouter::group(['prefix' => '/v1'], function () {
TestRouter::get('/test', 'DummyController@method1');
});
});
SimpleRouter::start();
TestRouter::debug('/api/v1/test', 'get');
}
public function testManyRoutes()
public function testMultipleRoutes()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/match');
SimpleRouter::request()->setMethod('get');
TestRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/test', 'DummyController@start');
TestRouter::group(['prefix' => '/v1'], function () {
TestRouter::get('/test', 'DummyController@method1');
});
});
SimpleRouter::get('/my/match', 'DummyController@start');
TestRouter::get('/my/match', 'DummyController@method1');
SimpleRouter::group(['prefix' => '/service'], function () {
TestRouter::group(['prefix' => '/service'], function () {
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/no-match', 'DummyController@start');
TestRouter::group(['prefix' => '/v1'], function () {
TestRouter::get('/no-match', 'DummyController@method1');
});
});
SimpleRouter::start();
TestRouter::debug('/my/match', 'get');
}
public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/fancy/url/1');
SimpleRouter::request()->setMethod('get');
// Test array name
SimpleRouter::get('/my/fancy/url/1', 'DummyController@start', ['as' => 'fancy1']);
TestRouter::get('/my/fancy/url/1', 'DummyController@method1', ['as' => 'fancy1']);
// Test method name
SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setName('fancy2');
TestRouter::get('/my/fancy/url/2', 'DummyController@method1')->setName('fancy2');
SimpleRouter::start();
TestRouter::debugNoReset('/my/fancy/url/1');
$this->assertEquals('/my/fancy/url/1/', SimpleRouter::getUrl('fancy1'));
$this->assertEquals('/my/fancy/url/2/', SimpleRouter::getUrl('fancy2'));
$this->assertEquals('/my/fancy/url/1/', TestRouter::getUrl('fancy1'));
$this->assertEquals('/my/fancy/url/2/', TestRouter::getUrl('fancy2'));
TestRouter::router()->reset();
}
+41
View File
@@ -0,0 +1,41 @@
<?php
class TestRouter extends \Pecee\SimpleRouter\SimpleRouter
{
public static function debugNoReset($testUri, $testMethod = 'get')
{
static::request()->setUri(new \Pecee\Http\Uri($testUri));
static::request()->setMethod($testMethod);
static::start();
}
public static function debug($testUri, $testMethod = 'get')
{
try {
static::debugNoReset($testUri, $testMethod);
} catch(\Exception $e) {
static::router()->reset();
throw $e;
}
static::router()->reset();
}
public static function debugOutput($testUri, $testMethod = 'get')
{
$response = null;
// Route request
ob_start();
static::debug($testUri, $testMethod);
$response = ob_get_contents();
ob_end_clean();
// Return response
return $response;
}
}
+12 -19
View File
@@ -3,39 +3,32 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php';
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
require_once 'Helpers/TestRouter.php';
class MiddlewareTest extends PHPUnit_Framework_TestCase
{
public function testMiddlewareFound()
{
$this->setExpectedException('MiddlewareLoadedException');
$this->setExpectedException(MiddlewareLoadedException::class);
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
TestRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
TestRouter::get('/my/test/url', 'DummyController@method1', ['middleware' => 'DummyMiddleware']);
});
SimpleRouter::start();
TestRouter::debug('/my/test/url', 'get');
}
public function testNestedMiddlewareLoad()
public function testNestedMiddlewareDontLoad()
{
$this->setExpectedException('MiddlewareLoadedException');
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler', 'middleware' => 'DummyMiddleware'], function () {
SimpleRouter::get('/my/test/url', 'DummyController@start');
TestRouter::group(['exceptionHandler' => 'ExceptionHandler', 'middleware' => 'DummyMiddleware'], function () {
TestRouter::get('/middleware', 'DummyController@method1');
});
SimpleRouter::start();
TestRouter::get('/my/test/url', 'DummyController@method1');
TestRouter::debug('/my/test/url', 'get');
}
}
@@ -0,0 +1,27 @@
<?php
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Exceptions/ExceptionHandlerException.php';
require_once 'Helpers/TestRouter.php';
class RouterCallbackExceptionHandlerTest extends PHPUnit_Framework_TestCase
{
public function testCallbackExceptionHandler()
{
$this->setExpectedException(ExceptionHandlerException::class);
// Match normal route on alias
TestRouter::get('/my-new-url', 'DummyController@method2');
TestRouter::get('/my-url', 'DummyController@method1');
TestRouter::error(function (\Pecee\Http\Request $request, \Exception $exception) {
throw new ExceptionHandlerException();
});
TestRouter::debugNoReset('/404-url', 'get');
TestRouter::router()->reset();
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
require_once 'Dummy/DummyController.php';
require_once 'Helpers/TestRouter.php';
class RouterControllerTest extends PHPUnit_Framework_TestCase
{
public function testGet()
{
// Match normal route on alias
TestRouter::controller('/url', 'DummyController');
$response = TestRouter::debugOutput('/url/test', 'get');
$this->assertEquals('getTest', $response);
}
public function testPost()
{
// Match normal route on alias
TestRouter::controller('/url', 'DummyController');
$response = TestRouter::debugOutput('/url/test', 'post');
$this->assertEquals('postTest', $response);
}
public function testPut()
{
// Match normal route on alias
TestRouter::controller('/url', 'DummyController');
$response = TestRouter::debugOutput('/url/test', 'put');
$this->assertEquals('putTest', $response);
}
}
+70
View File
@@ -0,0 +1,70 @@
<?php
require_once 'Dummy/ResourceController.php';
require_once 'Helpers/TestRouter.php';
class RouterResourceTest extends PHPUnit_Framework_TestCase
{
public function testResourceStore()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource', 'post');
$this->assertEquals('store', $response);
}
public function testResourceCreate()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource/create', 'get');
$this->assertEquals('create', $response);
}
public function testResourceIndex()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource', 'get');
$this->assertEquals('index', $response);
}
public function testResourceDestroy()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource/38', 'delete');
$this->assertEquals('destroy 38', $response);
}
public function testResourceEdit()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource/38/edit', 'get');
$this->assertEquals('edit 38', $response);
}
public function testResourceUpdate()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource/38', 'put');
$this->assertEquals('update 38', $response);
}
public function testResourceGet()
{
TestRouter::resource('/resource', 'ResourceController');
$response = TestRouter::debugOutput('/resource/38', 'get');
$this->assertEquals('show 38', $response);
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Exceptions/ResponseException.php';
require_once 'Dummy/Handler/ExceptionHandlerFirst.php';
require_once 'Dummy/Handler/ExceptionHandlerSecond.php';
require_once 'Dummy/Handler/ExceptionHandlerThird.php';
require_once 'Helpers/TestRouter.php';
class RouteRewriteTest extends PHPUnit_Framework_TestCase
{
/**
* Redirects to another route through 3 exception handlers.
*
* You will see "ExceptionHandler 1 loaded" 2 times. This happen because
* the exceptionhandler is asking the router to reload.
*
* That means that the exceptionhandler is loaded again, but this time
* the router ignores the same rewrite-route to avoid loop - loads
* the second which have same behavior and is also ignored before
* throwing the final Exception in ExceptionHandler 3.
*
* So this tests:
* 1. If ExceptionHandlers loads
* 2. If ExceptionHandlers load in the correct order
* 3. If ExceptionHandlers can rewrite the page on error
* 4. If the router can avoid redirect-loop due to developer has started loop.
* 5. And finally if we reaches the last exception-handler and that the correct
* exception-type is being thrown.
*/
public function testExceptionHandlerRewrite()
{
global $stack;
$stack = [];
TestRouter::group(['exceptionHandler' => [ExceptionHandlerFirst::class, ExceptionHandlerSecond::class]], function () {
TestRouter::group(['exceptionHandler' => ExceptionHandlerThird::class], function () {
TestRouter::get('/my-path', 'DummyController@method1');
});
});
try {
TestRouter::debug('/my-non-existing-path', 'get');
} catch (\ResponseException $e) {
}
$expectedStack = [
ExceptionHandlerFirst::class,
ExceptionHandlerSecond::class,
ExceptionHandlerThird::class,
];
$this->assertEquals($expectedStack, $stack);
}
public function testRewriteExceptionMessage()
{
$this->setExpectedException(\Pecee\SimpleRouter\Exceptions\NotFoundHttpException::class);
TestRouter::error(function (\Pecee\Http\Request $request, \Exception $error) {
if (strtolower($request->getUri()->getPath()) == '/my/test') {
$request->setRewriteUrl('/another-non-existing');
return $request;
}
});
TestRouter::debug('/my/test', 'get');
}
}
+72 -97
View File
@@ -3,12 +3,7 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Exceptions/ExceptionHandlerException.php';
require_once 'Dummy/Handler/TestExceptionHandlerFirst.php';
require_once 'Dummy/Handler/TestExceptionHandlerSecond.php';
require_once 'Dummy/Handler/TestExceptionHandlerThird.php';
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException as NotFoundHttpException;
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
require_once 'Helpers/TestRouter.php';
class RouterRouteTest extends PHPUnit_Framework_TestCase
{
@@ -16,113 +11,57 @@ class RouterRouteTest extends PHPUnit_Framework_TestCase
public function testMultiParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
TestRouter::get('/test-{param1}-{param2}', function ($param1, $param2) {
SimpleRouter::get('/test-{param1}-{param2}', function($param1, $param2) {
if($param1 === 'param1' && $param2 === 'param2') {
if ($param1 === 'param1' && $param2 === 'param2') {
$this->result = true;
}
});
SimpleRouter::start();
TestRouter::debug('/test-param1-param2', 'get');
$this->assertTrue($this->result);
}
/**
* Redirects to another route through 3 exception handlers.
*
* You will see "ExceptionHandler 1 loaded" 2 times. This happen because
* the exceptionhandler is asking the router to reload.
*
* That means that the exceptionhandler is loaded again, but this time
* the router ignores the same rewrite-route to avoid loop - loads
* the second which have same behavior and is also ignored before
* throwing the final Exception in ExceptionHandler 3.
*
* So this tests:
* 1. If ExceptionHandlers loads
* 2. If ExceptionHandlers load in the correct order
* 3. If ExceptionHandlers can rewrite the page on error
* 4. If the router can avoid redirect-loop due to developer has started loop.
* 5. And finally if we reaches the last exception-handler and that the correct
* exception-type is being thrown.
*/
public function testNotFound()
{
$this->setExpectedException('ExceptionHandlerException');
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
SimpleRouter::group(['exceptionHandler' => ['TestExceptionHandlerFirst', 'TestExceptionHandlerSecond']], function () {
SimpleRouter::group(['exceptionHandler' => 'TestExceptionHandlerThird'], function () {
SimpleRouter::get('/non-existing-path', 'DummyController@start');
});
});
SimpleRouter::start();
$this->setExpectedException('\Pecee\SimpleRouter\Exceptions\NotFoundHttpException');
TestRouter::get('/non-existing-path', 'DummyController@method1');
TestRouter::debug('/test-param1-param2', 'post');
}
public function testGet()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('get');
SimpleRouter::get('/my/test/url', 'DummyController@start');
SimpleRouter::start();
TestRouter::get('/my/test/url', 'DummyController@method1');
TestRouter::debug('/my/test/url', 'get');
}
public function testPost()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
SimpleRouter::post('/my/test/url', 'DummyController@start');
SimpleRouter::start();
TestRouter::post('/my/test/url', 'DummyController@method1');
TestRouter::debug('/my/test/url', 'post');
}
public function testPut()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('put');
SimpleRouter::put('/my/test/url', 'DummyController@start');
SimpleRouter::start();
TestRouter::put('/my/test/url', 'DummyController@method1');
TestRouter::debug('/my/test/url', 'put');
}
public function testDelete()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('delete');
SimpleRouter::delete('/my/test/url', 'DummyController@start');
SimpleRouter::start();
TestRouter::delete('/my/test/url', 'DummyController@method1');
TestRouter::debug('/my/test/url', 'delete');
}
public function testMethodNotAllowed()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
SimpleRouter::get('/my/test/url', 'DummyController@start');
TestRouter::get('/my/test/url', 'DummyController@method1');
try {
SimpleRouter::start();
TestRouter::debug('/my/test/url', 'post');
} catch (\Exception $e) {
$this->assertEquals(403, $e->getCode());
}
@@ -130,43 +69,79 @@ class RouterRouteTest extends PHPUnit_Framework_TestCase
public function testSimpleParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1');
TestRouter::get('/test-{param1}', 'DummyController@param');
$response = TestRouter::debugOutput('/test-param1', 'get');
SimpleRouter::get('/test-{param1}', 'DummyController@param');
SimpleRouter::start();
$this->assertEquals('param1', $response);
}
public function testPathParamRegex()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test/path/123123');
TestRouter::get('/{lang}/productscategories/{name}', 'DummyController@param', ['where' => ['lang' => '[a-z]+', 'name' => '[A-Za-z0-9\-]+']]);
$response = TestRouter::debugOutput('/it/productscategories/system', 'get');
SimpleRouter::get('/test/path/{myParam}', 'DummyController@param', ['where' => ['myParam' => '([0-9]+)']]);
SimpleRouter::start();
$this->assertEquals('it, system', $response);
}
public function testDomainRoute()
public function testDomainAllowedRoute()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test');
SimpleRouter::request()->setHost('hello.world.com');
$this->result = false;
SimpleRouter::group(['domain' => '{subdomain}.world.com'], function () {
SimpleRouter::get('/test', function ($subdomain = null) {
TestRouter::group(['domain' => '{subdomain}.world.com'], function () {
TestRouter::get('/test', function ($subdomain = null) {
$this->result = ($subdomain === 'hello');
});
});
SimpleRouter::start();
TestRouter::request()->setHost('hello.world.com');
TestRouter::debug('/test', 'get');
$this->assertTrue($this->result);
}
public function testDomainNotAllowedRoute()
{
$this->result = false;
TestRouter::group(['domain' => '{subdomain}.world.com'], function () {
TestRouter::get('/test', function ($subdomain = null) {
$this->result = ($subdomain === 'hello');
});
});
TestRouter::request()->setHost('other.world.com');
TestRouter::debug('/test', 'get');
$this->assertFalse($this->result);
}
public function testRegEx()
{
TestRouter::get('/my/{path}', 'DummyController@method1')->where(['path' => '[a-zA-Z\-]+']);
TestRouter::debug('/my/custom-path', 'get');
}
public function testDefaultParameterRegex()
{
TestRouter::get('/my/{path}', 'DummyController@param', ['defaultParameterRegex' => '[\w\-]+']);
$output = TestRouter::debugOutput('/my/custom-regex', 'get');
$this->assertEquals('custom-regex', $output);
}
public function testDefaultParameterRegexGroup()
{
TestRouter::group(['defaultParameterRegex' => '[\w\-]+'], function() {
TestRouter::get('/my/{path}', 'DummyController@param');
});
$output = TestRouter::debugOutput('/my/custom-regex', 'get');
$this->assertEquals('custom-regex', $output);
}
}
+105 -46
View File
@@ -3,111 +3,170 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php';
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
require_once 'Helpers/TestRouter.php';
class RouterUrlTest extends PHPUnit_Framework_TestCase
{
protected $result = false;
protected function getUrl($name = null, $parameters = null, array $getParams = [])
public function testIssue253()
{
return SimpleRouter::getUrl($name, $parameters, $getParams);
TestRouter::get('/', 'DummyController@method1');
TestRouter::get('/page/{id?}', 'DummyController@method1');
TestRouter::get('/test-output', function() {
return 'return value';
});
TestRouter::debugNoReset('/page/22', 'get');
$this->assertEquals('/page/{id?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::debugNoReset('/', 'get');
$this->assertEquals('/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
$output = TestRouter::debugOutput('/test-output', 'get');
$this->assertEquals('return value', $output);
TestRouter::router()->reset();
}
public function testUnicodeCharacters()
{
// Test spanish characters
TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-]+']);
TestRouter::debugNoReset('/cursos/listado/especialidad/cirugía local', 'get');
$this->assertEquals('/cursos/listado/{listado?}/{category?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
// Test danish characters
TestRouter::get('/kategori/økse', 'DummyController@method1', ['defaultParameterRegex' => '[\w\ø]+']);
TestRouter::debugNoReset('/kategori/økse', 'get');
$this->assertEquals('/kategori/økse/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-\í]+']);
TestRouter::debugNoReset('/test/Dermatología');
$parameters = TestRouter::request()->getLoadedRoute()->getParameters();
$this->assertEquals('Dermatología', $parameters['param']);
TestRouter::router()->reset();
}
public function testOptionalParameters()
{
TestRouter::get('/aviso/legal', 'DummyController@method1');
TestRouter::get('/aviso/{aviso}', 'DummyController@method1');
TestRouter::get('/pagina/{pagina}', 'DummyController@method1');
TestRouter::get('/{pagina?}', 'DummyController@method1');
TestRouter::debugNoReset('/aviso/optional', 'get');
$this->assertEquals('/aviso/{aviso}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::debugNoReset('/pagina/optional', 'get');
$this->assertEquals('/pagina/{pagina}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::debugNoReset('/optional', 'get');
$this->assertEquals('/{pagina?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::debugNoReset('/avisolegal', 'get');
$this->assertNotEquals('/aviso/{aviso}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::debugNoReset('/avisolegal', 'get');
$this->assertEquals('/{pagina?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
TestRouter::router()->reset();
}
public function testSimilarUrls()
{
// Match normal route on alias
TestRouter::resource('/url11', 'DummyController@method1');
TestRouter::resource('/url1', 'DummyController@method1', ['as' => 'match']);
TestRouter::debugNoReset('/url1', 'get');
$this->assertEquals(TestRouter::getUrl('match'), TestRouter::getUrl());
TestRouter::router()->reset();
}
public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/');
// Match normal route on alias
SimpleRouter::get('/', 'DummyController@silent', ['as' => 'home']);
TestRouter::get('/', 'DummyController@method1', ['as' => 'home']);
SimpleRouter::get('/about', 'DummyController@about');
TestRouter::get('/about', 'DummyController@about');
SimpleRouter::group(['prefix' => '/admin', 'as' => 'admin'], function () {
TestRouter::group(['prefix' => '/admin', 'as' => 'admin'], function () {
// Match route with prefix on alias
SimpleRouter::get('/{id?}', 'DummyController@start', ['as' => 'home']);
TestRouter::get('/{id?}', 'DummyController@method2', ['as' => 'home']);
// Match controller with prefix and alias
SimpleRouter::controller('/users', 'DummyController', ['as' => 'users']);
TestRouter::controller('/users', 'DummyController', ['as' => 'users']);
// Match controller with prefix and NO alias
SimpleRouter::controller('/pages', 'DummyController');
TestRouter::controller('/pages', 'DummyController');
});
SimpleRouter::group(['prefix' => 'api', 'as' => 'api'], function () {
TestRouter::group(['prefix' => 'api', 'as' => 'api'], function () {
// Match resource controller
SimpleRouter::resource('phones', 'DummyController');
TestRouter::resource('phones', 'DummyController');
});
SimpleRouter::controller('gadgets', 'DummyController', ['names' => ['getIphoneInfo' => 'iphone']]);
TestRouter::controller('gadgets', 'DummyController', ['names' => ['getIphoneInfo' => 'iphone']]);
// Match controller with no prefix and no alias
SimpleRouter::controller('/cats', 'CatsController');
TestRouter::controller('/cats', 'CatsController');
// Pretend to load page
SimpleRouter::start();
TestRouter::debugNoReset('/', 'get');
$this->assertEquals('/gadgets/iphoneinfo/', $this->getUrl('gadgets.iphone'));
$this->assertEquals('/gadgets/iphoneinfo/', TestRouter::getUrl('gadgets.iphone'));
$this->assertEquals('/api/phones/create/', $this->getUrl('api.phones.create'));
$this->assertEquals('/api/phones/create/', TestRouter::getUrl('api.phones.create'));
// Should match /
$this->assertEquals('/', $this->getUrl('home'));
$this->assertEquals('/', TestRouter::getUrl('home'));
// Should match /about/
$this->assertEquals('/about/', $this->getUrl('DummyController@about'));
$this->assertEquals('/about/', TestRouter::getUrl('DummyController@about'));
// Should match /admin/
$this->assertEquals('/admin/', $this->getUrl('DummyController@start'));
$this->assertEquals('/admin/', TestRouter::getUrl('DummyController@method2'));
// Should match /admin/
$this->assertEquals('/admin/', $this->getUrl('admin.home'));
$this->assertEquals('/admin/', TestRouter::getUrl('admin.home'));
// Should match /admin/2/
$this->assertEquals('/admin/2/', $this->getUrl('admin.home', ['id' => 2]));
$this->assertEquals('/admin/2/', TestRouter::getUrl('admin.home', ['id' => 2]));
// Should match /admin/users/
$this->assertEquals('/admin/users/', $this->getUrl('admin.users'));
$this->assertEquals('/admin/users/', TestRouter::getUrl('admin.users'));
// Should match /admin/users/home/
$this->assertEquals('/admin/users/home/', $this->getUrl('admin.users@home'));
$this->assertEquals('/admin/users/home/', TestRouter::getUrl('admin.users@home'));
// Should match /cats/
$this->assertEquals('/cats/', $this->getUrl('CatsController'));
$this->assertEquals('/cats/', TestRouter::getUrl('CatsController'));
// Should match /cats/view/
$this->assertEquals('/cats/view/', $this->getUrl('CatsController', 'view'));
$this->assertEquals('/cats/view/', TestRouter::getUrl('CatsController', 'view'));
// Should match /cats/view/
//$this->assertEquals('/cats/view/', $this->getUrl('CatsController', ['view']));
//$this->assertEquals('/cats/view/', TestRouter::getUrl('CatsController', ['view']));
// Should match /cats/view/666
$this->assertEquals('/cats/view/666/', $this->getUrl('CatsController@getView', ['666']));
$this->assertEquals('/cats/view/666/', TestRouter::getUrl('CatsController@getView', ['666']));
// Should match /funny/man/
$this->assertEquals('/funny/man/', $this->getUrl('/funny/man'));
$this->assertEquals('/funny/man/', TestRouter::getUrl('/funny/man'));
// Should match /?jackdaniels=true&cola=yeah
$this->assertEquals('/?jackdaniels=true&cola=yeah', $this->getUrl('home', null, ['jackdaniels' => 'true', 'cola' => 'yeah']));
$this->assertEquals('/?jackdaniels=true&cola=yeah', TestRouter::getUrl('home', null, ['jackdaniels' => 'true', 'cola' => 'yeah']));
}
public function testRegEx()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/custom-path');
SimpleRouter::get('/my/{path}', 'DummyController@start')->where(['path' => '[a-zA-Z\-]+']);
SimpleRouter::start();
TestRouter::router()->reset();
}