├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── phpunit.xml.dist ├── src └── Stack │ ├── LazyHttpKernel.php │ └── functions.php └── tests └── unit └── Stack └── LazyHttpKernelTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | * 1.0.0 (2013-12-04) 5 | 6 | * Initial release. 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Igor Wiedler 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stack/LazyHttpKernel 2 | 3 | HttpKernelInterface lazy proxy. 4 | 5 | This is useful in combination with something like UrlMap, where sub-kernels 6 | are only created conditionally. 7 | 8 | ## Example 9 | 10 | The basic example, assumes that `app.php` returns an instance of 11 | `HttpKernelInterface`: 12 | 13 | ```php 14 | use Stack\LazyHttpKernel; 15 | 16 | $app = new LazyHttpKernel(function () { 17 | return require __DIR__.'/../app.php'; 18 | }); 19 | ``` 20 | 21 | As a shortcut, you can use the `Stack\lazy` function: 22 | 23 | ```php 24 | use Stack; 25 | 26 | $app = Stack\lazy(function () { 27 | return require __DIR__.'/../app.php'; 28 | }); 29 | ``` 30 | 31 | When combined with the UrlMap middleware it makes a bit more sense: 32 | 33 | ```php 34 | use Stack; 35 | use Stack\UrlMap; 36 | 37 | $app = ...; 38 | 39 | $app = new UrlMap($app, [ 40 | '/foo' => Stack\lazy(function () { 41 | return require __DIR__.'/../app.php'; 42 | }) 43 | ]); 44 | ``` 45 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stack/lazy-http-kernel", 3 | "description": "HttpKernelInterface lazy proxy.", 4 | "keywords": ["stack"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Igor Wiedler", 9 | "email": "igor@wiedler.ch" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.4.0", 14 | "symfony/http-foundation": "~2.1", 15 | "symfony/http-kernel": "~2.1" 16 | }, 17 | "require-dev": { 18 | "stack/callable-http-kernel": "~1.0@dev", 19 | "stack/url-map": "~1.0@dev" 20 | }, 21 | "autoload": { 22 | "psr-0": { "Stack": "src" }, 23 | "files": ["src/Stack/functions.php"] 24 | }, 25 | "extra": { 26 | "branch-alias": { "dev-master": "1.0-dev" } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" 5 | ], 6 | "hash": "434a519581bef6805d64c41dcd400cc0", 7 | "packages": [ 8 | { 9 | "name": "psr/log", 10 | "version": "1.0.0", 11 | "source": { 12 | "type": "git", 13 | "url": "https://github.com/php-fig/log", 14 | "reference": "1.0.0" 15 | }, 16 | "dist": { 17 | "type": "zip", 18 | "url": "https://github.com/php-fig/log/archive/1.0.0.zip", 19 | "reference": "1.0.0", 20 | "shasum": "" 21 | }, 22 | "type": "library", 23 | "autoload": { 24 | "psr-0": { 25 | "Psr\\Log\\": "" 26 | } 27 | }, 28 | "notification-url": "https://packagist.org/downloads/", 29 | "license": [ 30 | "MIT" 31 | ], 32 | "authors": [ 33 | { 34 | "name": "PHP-FIG", 35 | "homepage": "http://www.php-fig.org/" 36 | } 37 | ], 38 | "description": "Common interface for logging libraries", 39 | "keywords": [ 40 | "log", 41 | "psr", 42 | "psr-3" 43 | ], 44 | "time": "2012-12-21 11:40:51" 45 | }, 46 | { 47 | "name": "symfony/debug", 48 | "version": "v2.3.6", 49 | "target-dir": "Symfony/Component/Debug", 50 | "source": { 51 | "type": "git", 52 | "url": "https://github.com/symfony/Debug.git", 53 | "reference": "7f671456b9617d0a54f04597ae1c1ed3a1e858fd" 54 | }, 55 | "dist": { 56 | "type": "zip", 57 | "url": "https://api.github.com/repos/symfony/Debug/zipball/7f671456b9617d0a54f04597ae1c1ed3a1e858fd", 58 | "reference": "7f671456b9617d0a54f04597ae1c1ed3a1e858fd", 59 | "shasum": "" 60 | }, 61 | "require": { 62 | "php": ">=5.3.3" 63 | }, 64 | "require-dev": { 65 | "symfony/http-foundation": "~2.1", 66 | "symfony/http-kernel": "~2.1" 67 | }, 68 | "suggest": { 69 | "symfony/class-loader": "", 70 | "symfony/http-foundation": "", 71 | "symfony/http-kernel": "" 72 | }, 73 | "type": "library", 74 | "extra": { 75 | "branch-alias": { 76 | "dev-master": "2.3-dev" 77 | } 78 | }, 79 | "autoload": { 80 | "psr-0": { 81 | "Symfony\\Component\\Debug\\": "" 82 | } 83 | }, 84 | "notification-url": "https://packagist.org/downloads/", 85 | "license": [ 86 | "MIT" 87 | ], 88 | "authors": [ 89 | { 90 | "name": "Fabien Potencier", 91 | "email": "fabien@symfony.com" 92 | }, 93 | { 94 | "name": "Symfony Community", 95 | "homepage": "http://symfony.com/contributors" 96 | } 97 | ], 98 | "description": "Symfony Debug Component", 99 | "homepage": "http://symfony.com", 100 | "time": "2013-09-19 09:47:13" 101 | }, 102 | { 103 | "name": "symfony/event-dispatcher", 104 | "version": "v2.3.6", 105 | "target-dir": "Symfony/Component/EventDispatcher", 106 | "source": { 107 | "type": "git", 108 | "url": "https://github.com/symfony/EventDispatcher.git", 109 | "reference": "7fc72a7a346a1887d3968cc1ce5642a15cd182e9" 110 | }, 111 | "dist": { 112 | "type": "zip", 113 | "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/7fc72a7a346a1887d3968cc1ce5642a15cd182e9", 114 | "reference": "7fc72a7a346a1887d3968cc1ce5642a15cd182e9", 115 | "shasum": "" 116 | }, 117 | "require": { 118 | "php": ">=5.3.3" 119 | }, 120 | "require-dev": { 121 | "symfony/dependency-injection": "~2.0" 122 | }, 123 | "suggest": { 124 | "symfony/dependency-injection": "", 125 | "symfony/http-kernel": "" 126 | }, 127 | "type": "library", 128 | "extra": { 129 | "branch-alias": { 130 | "dev-master": "2.3-dev" 131 | } 132 | }, 133 | "autoload": { 134 | "psr-0": { 135 | "Symfony\\Component\\EventDispatcher\\": "" 136 | } 137 | }, 138 | "notification-url": "https://packagist.org/downloads/", 139 | "license": [ 140 | "MIT" 141 | ], 142 | "authors": [ 143 | { 144 | "name": "Fabien Potencier", 145 | "email": "fabien@symfony.com" 146 | }, 147 | { 148 | "name": "Symfony Community", 149 | "homepage": "http://symfony.com/contributors" 150 | } 151 | ], 152 | "description": "Symfony EventDispatcher Component", 153 | "homepage": "http://symfony.com", 154 | "time": "2013-09-19 09:45:20" 155 | }, 156 | { 157 | "name": "symfony/http-foundation", 158 | "version": "v2.3.6", 159 | "target-dir": "Symfony/Component/HttpFoundation", 160 | "source": { 161 | "type": "git", 162 | "url": "https://github.com/symfony/HttpFoundation.git", 163 | "reference": "59e712338cd05463ebcb8da6422a01b1291871e3" 164 | }, 165 | "dist": { 166 | "type": "zip", 167 | "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/59e712338cd05463ebcb8da6422a01b1291871e3", 168 | "reference": "59e712338cd05463ebcb8da6422a01b1291871e3", 169 | "shasum": "" 170 | }, 171 | "require": { 172 | "php": ">=5.3.3" 173 | }, 174 | "type": "library", 175 | "extra": { 176 | "branch-alias": { 177 | "dev-master": "2.3-dev" 178 | } 179 | }, 180 | "autoload": { 181 | "psr-0": { 182 | "Symfony\\Component\\HttpFoundation\\": "" 183 | }, 184 | "classmap": [ 185 | "Symfony/Component/HttpFoundation/Resources/stubs" 186 | ] 187 | }, 188 | "notification-url": "https://packagist.org/downloads/", 189 | "license": [ 190 | "MIT" 191 | ], 192 | "authors": [ 193 | { 194 | "name": "Fabien Potencier", 195 | "email": "fabien@symfony.com" 196 | }, 197 | { 198 | "name": "Symfony Community", 199 | "homepage": "http://symfony.com/contributors" 200 | } 201 | ], 202 | "description": "Symfony HttpFoundation Component", 203 | "homepage": "http://symfony.com", 204 | "time": "2013-09-29 19:41:41" 205 | }, 206 | { 207 | "name": "symfony/http-kernel", 208 | "version": "v2.3.6", 209 | "target-dir": "Symfony/Component/HttpKernel", 210 | "source": { 211 | "type": "git", 212 | "url": "https://github.com/symfony/HttpKernel.git", 213 | "reference": "9ace7b963fa6d2eae8471c246e6fabc2ef714566" 214 | }, 215 | "dist": { 216 | "type": "zip", 217 | "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/9ace7b963fa6d2eae8471c246e6fabc2ef714566", 218 | "reference": "9ace7b963fa6d2eae8471c246e6fabc2ef714566", 219 | "shasum": "" 220 | }, 221 | "require": { 222 | "php": ">=5.3.3", 223 | "psr/log": "~1.0", 224 | "symfony/debug": "~2.3", 225 | "symfony/event-dispatcher": "~2.1", 226 | "symfony/http-foundation": "~2.2" 227 | }, 228 | "require-dev": { 229 | "symfony/browser-kit": "~2.2", 230 | "symfony/class-loader": "~2.1", 231 | "symfony/config": "~2.0", 232 | "symfony/console": "~2.2", 233 | "symfony/dependency-injection": "~2.0", 234 | "symfony/finder": "~2.0", 235 | "symfony/process": "~2.0", 236 | "symfony/routing": "~2.2", 237 | "symfony/stopwatch": "~2.2", 238 | "symfony/templating": "~2.2" 239 | }, 240 | "suggest": { 241 | "symfony/browser-kit": "", 242 | "symfony/class-loader": "", 243 | "symfony/config": "", 244 | "symfony/console": "", 245 | "symfony/dependency-injection": "", 246 | "symfony/finder": "" 247 | }, 248 | "type": "library", 249 | "extra": { 250 | "branch-alias": { 251 | "dev-master": "2.3-dev" 252 | } 253 | }, 254 | "autoload": { 255 | "psr-0": { 256 | "Symfony\\Component\\HttpKernel\\": "" 257 | } 258 | }, 259 | "notification-url": "https://packagist.org/downloads/", 260 | "license": [ 261 | "MIT" 262 | ], 263 | "authors": [ 264 | { 265 | "name": "Fabien Potencier", 266 | "email": "fabien@symfony.com" 267 | }, 268 | { 269 | "name": "Symfony Community", 270 | "homepage": "http://symfony.com/contributors" 271 | } 272 | ], 273 | "description": "Symfony HttpKernel Component", 274 | "homepage": "http://symfony.com", 275 | "time": "2013-10-10 13:24:22" 276 | } 277 | ], 278 | "packages-dev": [ 279 | { 280 | "name": "stack/callable-http-kernel", 281 | "version": "dev-master", 282 | "source": { 283 | "type": "git", 284 | "url": "https://github.com/stackphp/CallableHttpKernel.git", 285 | "reference": "97f6bd2aaf0f173a902dfd6bd4ffa558a799531d" 286 | }, 287 | "dist": { 288 | "type": "zip", 289 | "url": "https://api.github.com/repos/stackphp/CallableHttpKernel/zipball/97f6bd2aaf0f173a902dfd6bd4ffa558a799531d", 290 | "reference": "97f6bd2aaf0f173a902dfd6bd4ffa558a799531d", 291 | "shasum": "" 292 | }, 293 | "require": { 294 | "php": ">=5.3.0", 295 | "symfony/http-foundation": "~2.1", 296 | "symfony/http-kernel": "~2.1" 297 | }, 298 | "type": "library", 299 | "extra": { 300 | "branch-alias": { 301 | "dev-master": "1.0-dev" 302 | } 303 | }, 304 | "autoload": { 305 | "psr-0": { 306 | "Stack": "src" 307 | } 308 | }, 309 | "notification-url": "https://packagist.org/downloads/", 310 | "license": [ 311 | "MIT" 312 | ], 313 | "authors": [ 314 | { 315 | "name": "Igor Wiedler", 316 | "email": "igor@wiedler.ch", 317 | "homepage": "http://wiedler.ch/igor/" 318 | } 319 | ], 320 | "description": "HttpKernelInterface implementation based on callables.", 321 | "keywords": [ 322 | "stack" 323 | ], 324 | "time": "2013-10-25 14:27:17" 325 | }, 326 | { 327 | "name": "stack/url-map", 328 | "version": "dev-master", 329 | "source": { 330 | "type": "git", 331 | "url": "https://github.com/stackphp/url-map.git", 332 | "reference": "ff0e849b2c5958e944ae4bc7bc1d8587598cca7d" 333 | }, 334 | "dist": { 335 | "type": "zip", 336 | "url": "https://api.github.com/repos/stackphp/url-map/zipball/ff0e849b2c5958e944ae4bc7bc1d8587598cca7d", 337 | "reference": "ff0e849b2c5958e944ae4bc7bc1d8587598cca7d", 338 | "shasum": "" 339 | }, 340 | "require": { 341 | "php": ">=5.4.0", 342 | "symfony/http-foundation": "~2.1", 343 | "symfony/http-kernel": "~2.1" 344 | }, 345 | "require-dev": { 346 | "phpunit/phpunit": "~3.7", 347 | "silex/silex": "~1.0@dev", 348 | "stack/builder": "~1.0@dev", 349 | "stack/callable-http-kernel": "~1.0@dev" 350 | }, 351 | "type": "library", 352 | "extra": { 353 | "branch-alias": { 354 | "dev-master": "1.0-dev" 355 | } 356 | }, 357 | "autoload": { 358 | "psr-0": { 359 | "Stack\\": "src/" 360 | } 361 | }, 362 | "notification-url": "https://packagist.org/downloads/", 363 | "license": [ 364 | "MIT" 365 | ], 366 | "authors": [ 367 | { 368 | "name": "Christoph Hochstrasser", 369 | "email": "christoph.hochstrasser@gmail.com", 370 | "homepage": "http://christophh.net" 371 | } 372 | ], 373 | "description": "URL Map middleware.", 374 | "time": "2013-05-26 09:00:11" 375 | } 376 | ], 377 | "aliases": [ 378 | 379 | ], 380 | "minimum-stability": "stable", 381 | "stability-flags": { 382 | "stack/callable-http-kernel": 20, 383 | "stack/url-map": 20 384 | }, 385 | "platform": { 386 | "php": ">=5.4.0" 387 | }, 388 | "platform-dev": [ 389 | 390 | ] 391 | } 392 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | ./tests/unit/ 10 | 11 | 12 | 13 | 14 | 15 | ./tests/integration/ 16 | 17 | 18 | 19 | 20 | 21 | ./tests/functional/ 22 | 23 | 24 | 25 | 26 | 27 | ./src/ 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Stack/LazyHttpKernel.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 17 | } 18 | 19 | public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) 20 | { 21 | return $this->createApp()->handle($request, $type, $catch); 22 | } 23 | 24 | private function createApp() 25 | { 26 | $this->app = $this->app ?: call_user_func($this->factory); 27 | 28 | return $this->app; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Stack/functions.php: -------------------------------------------------------------------------------- 1 | createHelloKernel(); 16 | }; 17 | 18 | $kernel = new LazyHttpKernel($factory); 19 | 20 | $request = Request::create('/'); 21 | $response = $kernel->handle($request); 22 | $this->assertEquals(new Response('Hello World!'), $response); 23 | } 24 | 25 | /** @test */ 26 | public function handleShouldInvokeFactoryJustOnce() 27 | { 28 | $factoryCalled = 0; 29 | 30 | $factory = function () use (&$factoryCalled) { 31 | $factoryCalled++; 32 | return $this->createHelloKernel(); 33 | }; 34 | 35 | $kernel = new LazyHttpKernel($factory); 36 | 37 | $request = Request::create('/'); 38 | $response = $kernel->handle($request); 39 | 40 | $this->assertSame(1, $factoryCalled); 41 | } 42 | 43 | /** @test */ 44 | public function handleShouldReuseCreatedApp() 45 | { 46 | $factoryCalled = 0; 47 | 48 | $factory = function () use (&$factoryCalled) { 49 | $factoryCalled++; 50 | return $this->createHelloKernel(); 51 | }; 52 | 53 | $kernel = new LazyHttpKernel($factory); 54 | 55 | $request = Request::create('/'); 56 | $response = $kernel->handle($request); 57 | $response = $kernel->handle($request); 58 | 59 | $this->assertSame(1, $factoryCalled); 60 | } 61 | 62 | public function testWithUrlMap() 63 | { 64 | $fooFactoryCalled = 0; 65 | $barFactoryCalled = 0; 66 | 67 | $foo = new LazyHttpKernel(function () use (&$fooFactoryCalled) { 68 | $fooFactoryCalled++; 69 | return $this->createKernel('foo'); 70 | }); 71 | 72 | $bar = new LazyHttpKernel(function () use (&$barFactoryCalled) { 73 | $barFactoryCalled++; 74 | return $this->createKernel('bar'); 75 | }); 76 | 77 | $app = $this->createHelloKernel(); 78 | $kernel = new UrlMap($app, [ 79 | '/foo' => $foo, 80 | '/bar' => $bar, 81 | ]); 82 | 83 | $request = Request::create('/foo'); 84 | $response = $kernel->handle($request); 85 | 86 | $this->assertSame(1, $fooFactoryCalled); 87 | $this->assertSame(0, $barFactoryCalled); 88 | } 89 | 90 | public function testShortcutFunction() 91 | { 92 | $kernel = lazy(function () { 93 | return $this->createHelloKernel(); 94 | }); 95 | 96 | $this->assertInstanceOf('Stack\LazyHttpKernel', $kernel); 97 | $this->assertSame('Hello World!', $kernel->handle(Request::create('/'))->getContent()); 98 | } 99 | 100 | private function createHelloKernel() 101 | { 102 | return $this->createKernel('Hello World!'); 103 | } 104 | 105 | private function createKernel($body) 106 | { 107 | return new CallableHttpKernel(function (Request $request) use ($body) { 108 | return new Response($body); 109 | }); 110 | } 111 | } 112 | --------------------------------------------------------------------------------