├── .github └── workflows │ └── php.yml ├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── CHANGES.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── autoload.php ├── composer.json ├── config ├── Common.php ├── WebKernelTest.php └── _env.php ├── phpunit.php ├── phpunit.xml.dist ├── src ├── AbstractResponder.php ├── CaughtException.php ├── CaughtExceptionResponder.php ├── MissingAction.php ├── MissingActionResponder.php ├── MissingRoute.php ├── MissingRouteResponder.php ├── WebKernel.php ├── WebKernelDispatcher.php └── WebKernelRouter.php └── tests └── WebKernelTest.php /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | branches: [ 4.x ] 6 | pull_request: 7 | branches: [ 4.x ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ${{ matrix.operating-system }} 13 | strategy: 14 | matrix: 15 | operating-system: [ubuntu-latest, windows-latest, macOS-latest] 16 | php-versions: ['7.2', '7.3'] 17 | name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} 18 | 19 | steps: 20 | - uses: actions/checkout@v2 21 | 22 | - name: Install PHP 23 | uses: shivammathur/setup-php@v2 24 | with: 25 | php-version: ${{ matrix.php-versions }} 26 | extensions: intl #optional 27 | ini-values: "post_max_size=256M" #optional 28 | - name: Check PHP Version 29 | run: php -v 30 | 31 | - name: Validate composer.json and composer.lock 32 | run: composer validate --strict 33 | 34 | - name: Cache Composer packages 35 | id: composer-cache 36 | uses: actions/cache@v2 37 | with: 38 | path: vendor 39 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 40 | restore-keys: | 41 | ${{ runner.os }}-php- 42 | 43 | - name: Install dependencies 44 | run: composer install --prefer-dist --no-progress 45 | 46 | # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" 47 | # Docs: https://getcomposer.org/doc/articles/scripts.md 48 | 49 | - name: Run test suite 50 | run: composer run-script test 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor 3 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: ["src/*"] 3 | tools: 4 | external_code_coverage: true 5 | php_code_coverage: true 6 | php_sim: true 7 | php_mess_detector: true 8 | php_pdepend: true 9 | php_analyzer: true 10 | php_cpd: true 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: php 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - hhvm 8 | - 7 9 | before_script: 10 | - composer self-update 11 | - composer install 12 | script: 13 | - phpunit --coverage-clover=coverage.clover 14 | after_script: 15 | - wget https://scrutinizer-ci.com/ocular.phar 16 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 17 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | This is primarily a hygiene release, with one minor bugfix. 2 | 3 | - (FIX) In WebKernelDispatcher::__invoke, use Dispatcher::getObjectParam 4 | - (HYG) Update license year and remove branch alias. 5 | - (HYG) Improve PSR-2 compliance. 6 | - (HYG) Update Travis configurations. 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We are happy to review any contributions you want to make. When contributing, please follow the rules outlined at . 4 | 5 | The time between submitting a contribution and its review one may be extensive; do not be discouraged if there is not immediate feedback. 6 | 7 | Thanks! 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2016, Aura for PHP 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aura.Web_Kernel 2 | 3 | This is a kernel for the [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) package. 4 | 5 | ## Foreword 6 | 7 | ### Requirements 8 | 9 | This kernel requires PHP 5.4 or later; we recommend using the latest available version of PHP as a matter of principle. 10 | 11 | Unlike Aura library packages, this kernel package has userland dependencies, which themselves may have other dependencies: 12 | 13 | - [aura/project-kernel](https://packagist.org/packages/aura/project-kernel) 14 | - [aura/dispatcher](https://packagist.org/packages/aura/dispatcher) 15 | - [aura/router](https://packagist.org/packages/aura/router) 16 | - [aura/web](https://packagist.org/packages/aura/web) 17 | - [psr/log](https://packagist.org/packages/psr/log) 18 | 19 | ### Installation 20 | 21 | This kernel is installable and autoloadable via Composer with the following 22 | `require` element in your `composer.json` file: 23 | 24 | "require": { 25 | "aura/web-kernel": "dev-develop-2" 26 | } 27 | 28 | Alternatively, download or clone this repository, then require or include its 29 | _autoload.php_ file. 30 | 31 | ### Tests 32 | 33 | [![Build Status](https://travis-ci.org/auraphp/Aura.Web_Kernel.png?branch=develop-2)](https://travis-ci.org/auraphp/Aura.Web_Kernel) 34 | 35 | To run the unit tests at the command line, issue `composer install` and then `phpunit` at the package root. This requires [Composer](http://getcomposer.org/) to be available as `composer`, and [PHPUnit](http://phpunit.de/) to be available as `phpunit`. 36 | 37 | 38 | ### PSR Compliance 39 | 40 | This kernel attempts to comply with [PSR-1][], [PSR-2][], and [PSR-4][]. If 41 | you notice compliance oversights, please send a patch via pull request. 42 | 43 | [PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md 44 | [PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md 45 | [PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md 46 | 47 | ### Community 48 | 49 | To ask questions, provide feedback, or otherwise communicate with the Aura community, please join our [Google Group](http://groups.google.com/group/auraphp), follow [@auraphp on Twitter](http://twitter.com/auraphp), or chat with us on #auraphp on Freenode. 50 | 51 | ### Services 52 | 53 | This kernel defines the following service objects in the _Container_: 54 | 55 | - `aura/web-kernel:dispatcher`: an instance of _Aura\Dispatcher\Dispatcher_ 56 | - `aura/web-kernel:request`: an instance of _Aura\Web\Request_ 57 | - `aura/web-kernel:response`: an instance of _Aura\Web\Response_ 58 | - `aura/web-kernel:router`: an instance of _Aura\Router\Router_ 59 | 60 | Note that service definitions set at the kernel level may be reset at the project level. 61 | -------------------------------------------------------------------------------- /autoload.php: -------------------------------------------------------------------------------- 1 | array( 10 | __DIR__ . '/config', 11 | __DIR__ . '/tests/kernel/config', 12 | ), 13 | "{$ns}\\" => array( 14 | __DIR__ . '/src', 15 | __DIR__ . '/tests/kernel/src', 16 | ), 17 | ); 18 | 19 | // go through the prefixes 20 | foreach ($prefixes as $prefix => $dirs) { 21 | 22 | // does the requested class match the namespace prefix? 23 | $prefix_len = strlen($prefix); 24 | if (substr($class, 0, $prefix_len) !== $prefix) { 25 | continue; 26 | } 27 | 28 | // strip the prefix off the class 29 | $class = substr($class, $prefix_len); 30 | 31 | // a partial filename 32 | $part = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; 33 | 34 | // go through the directories to find classes 35 | foreach ($dirs as $dir) { 36 | $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir); 37 | $file = $dir . DIRECTORY_SEPARATOR . $part; 38 | if (is_readable($file)) { 39 | require $file; 40 | return; 41 | } 42 | } 43 | } 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aura/web-kernel", 3 | "type": "library", 4 | "description": "The kernel files for an Aura web project.", 5 | "keywords": [ 6 | "web", 7 | "kernel" 8 | ], 9 | "homepage": "https://github.com/auraphp/Aura.Web_Kernel", 10 | "license": "BSD-2-Clause", 11 | "authors": [ 12 | { 13 | "name": "Aura.Web_Kernel Contributors", 14 | "homepage": "https://github.com/auraphp/Aura.Web_Kernel/contributors" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=5.4.0", 19 | "aura/project-kernel": "~2.0", 20 | "aura/dispatcher": "~2.0", 21 | "aura/router": "~2.0", 22 | "aura/web": "~2.0" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "~7" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Aura\\Web_Kernel\\": "src/", 30 | "Aura\\Web_Kernel\\_Config\\": "config/" 31 | } 32 | }, 33 | "extra": { 34 | "aura": { 35 | "type": "kernel", 36 | "config": { 37 | "common": "Aura\\Web_Kernel\\_Config\\Common", 38 | "web-kernel-test": "Aura\\Web_Kernel\\_Config\\WebKernelTest" 39 | } 40 | } 41 | }, 42 | "autoload-dev": { 43 | "psr-4": { 44 | "Aura\\Web_Kernel\\": "tests/", 45 | "Aura\\Di\\": "vendor/aura/di/tests/", 46 | "Aura\\Web\\": "vendor/aura/web/tests/" 47 | } 48 | }, 49 | "scripts": { 50 | "test": [ 51 | "@composer install", 52 | "./vendor/bin/phpunit" 53 | ] 54 | }, 55 | "scripts-descriptions": { 56 | "test": "Run unit tests" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /config/Common.php: -------------------------------------------------------------------------------- 1 | set('aura/web-kernel:request', $di->lazyNew('Aura\Web\Request')); 13 | $di->set('aura/web-kernel:response', $di->lazyNew('Aura\Web\Response')); 14 | $di->set('aura/web-kernel:router', $di->lazyNew('Aura\Router\Router')); 15 | $di->set('aura/web-kernel:dispatcher', $di->lazyNew('Aura\Dispatcher\Dispatcher')); 16 | 17 | // Aura\Web\ResponseSender 18 | $di->params['Aura\Web\ResponseSender'] = array( 19 | 'response' => $di->lazyGet('aura/web-kernel:response'), 20 | ); 21 | 22 | // Aura\Web_Kernel\Abstract_Responder 23 | $di->params['Aura\Web_Kernel\AbstractResponder'] = array( 24 | 'response' => $di->lazyGet('aura/web-kernel:response'), 25 | ); 26 | 27 | // Aura\Web_Kernel\CaughtException 28 | $di->params['Aura\Web_Kernel\CaughtException'] = array( 29 | 'request' => $di->lazyGet('aura/web-kernel:request'), 30 | 'responder' => $di->lazyNew('Aura\Web_Kernel\CaughtExceptionResponder'), 31 | ); 32 | 33 | // Aura\Web_Kernel\MissingAction 34 | $di->params['Aura\Web_Kernel\MissingAction'] = array( 35 | 'request' => $di->lazyGet('aura/web-kernel:request'), 36 | 'responder' => $di->lazyNew('Aura\Web_Kernel\MissingActionResponder'), 37 | ); 38 | 39 | // Aura\Web_Kernel\MissingRoute 40 | $di->params['Aura\Web_Kernel\MissingRoute'] = array( 41 | 'request' => $di->lazyGet('aura/web-kernel:request'), 42 | 'responder' => $di->lazyNew('Aura\Web_Kernel\MissingRouteResponder'), 43 | ); 44 | 45 | // Aura\Web_Kernel\WebKernel 46 | $di->params['Aura\Web_Kernel\WebKernel'] = array( 47 | 'router' => $di->lazyNew('Aura\Web_Kernel\WebKernelRouter'), 48 | 'dispatcher' => $di->lazyNew('Aura\Web_Kernel\WebKernelDispatcher'), 49 | 'response_sender' => $di->lazyNew('Aura\Web\ResponseSender'), 50 | ); 51 | 52 | // Aura\Web_Kernel\WebKernelDispatcher 53 | $di->params['Aura\Web_Kernel\WebKernelDispatcher'] = array( 54 | 'request' => $di->lazyGet('aura/web-kernel:request'), 55 | 'dispatcher' => $di->lazyGet('aura/web-kernel:dispatcher'), 56 | 'logger' => $di->lazyGet('aura/project-kernel:logger'), 57 | ); 58 | 59 | // Aura\Web_Kernel\WebKernelRouter 60 | $di->params['Aura\Web_Kernel\WebKernelRouter'] = array( 61 | 'request' => $di->lazyGet('aura/web-kernel:request'), 62 | 'router' => $di->lazyGet('aura/web-kernel:router'), 63 | 'logger' => $di->lazyGet('aura/project-kernel:logger'), 64 | ); 65 | 66 | } 67 | 68 | public function modify(Container $di) 69 | { 70 | $dispatcher = $di->get('aura/web-kernel:dispatcher'); 71 | $request = $di->get('aura/web-kernel:request'); 72 | $response = $di->get('aura/web-kernel:response'); 73 | 74 | // use 'action' from the route params 75 | $dispatcher->setObjectParam('action'); 76 | 77 | // the url has no matching route 78 | $dispatcher->setObject( 79 | 'aura.web_kernel.missing_route', 80 | $di->lazyNew('Aura\Web_Kernel\MissingRoute') 81 | ); 82 | 83 | // the action was not found 84 | $dispatcher->setObject( 85 | 'aura.web_kernel.missing_action', 86 | $di->lazyNew('Aura\Web_Kernel\MissingAction') 87 | ); 88 | 89 | // the kernel caught an exception 90 | $dispatcher->setObject( 91 | 'aura.web_kernel.caught_exception', 92 | $di->lazyNew('Aura\Web_Kernel\CaughtException') 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /config/WebKernelTest.php: -------------------------------------------------------------------------------- 1 | params['Aura\Web_Kernel\WebKernel']['response_sender'] = $di->lazyNew( 12 | 'Aura\Web\FakeResponseSender' 13 | ); 14 | } 15 | 16 | public function modify(Container $di) 17 | { 18 | $request = $di->get('aura/web-kernel:request'); 19 | $response = $di->get('aura/web-kernel:response'); 20 | $router = $di->get('aura/web-kernel:router'); 21 | 22 | $router->add(null, '/aura/web-kernel/integration/hello') 23 | ->addValues(array( 24 | 'action' => function () use ($request, $response) { 25 | $response->headers->set('X-Hello', 'World'); 26 | $response->cookies->set('hello', 'world'); 27 | $response->content->set('Hello World!'); 28 | }, 29 | )); 30 | 31 | $router->add(null, '/aura/web-kernel/integration/missing-action') 32 | ->addValues(array( 33 | 'action' => 'no-such-action', 34 | 'true' => true, 35 | 'false' => false, 36 | 'null' => null, 37 | 'object' => $this, 38 | 'int' => 88, 39 | 'float' => 12.34 40 | )); 41 | 42 | $router->add(null, '/aura/web-kernel/integration/throw-exception') 43 | ->addValues(array( 44 | 'action' => function () { 45 | throw new \Exception('Mock exception'); 46 | }, 47 | )); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /config/_env.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./tests 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/AbstractResponder.php: -------------------------------------------------------------------------------- 1 | response = $response; 53 | } 54 | 55 | /** 56 | * 57 | * Sets data for building the response. 58 | * 59 | * @param array $data Data for the response. 60 | * 61 | * @return null 62 | * 63 | */ 64 | public function setData(array $data) 65 | { 66 | $this->data = $data; 67 | } 68 | 69 | /** 70 | * 71 | * Invokes the responder. 72 | * 73 | * @return null 74 | * 75 | */ 76 | abstract public function __invoke(); 77 | 78 | /** 79 | * 80 | * Exports the params in an easier-to-read format, especially for objects. 81 | * 82 | * @param array $params 83 | * 84 | */ 85 | protected function exportParams($params) 86 | { 87 | if (! $params) { 88 | return 'none'; 89 | } 90 | 91 | $export = array(); 92 | foreach ($params as $key => $val) { 93 | $key = var_export($key, true); 94 | if (is_object($val)) { 95 | $export[] = " {$key} => " . get_class($val); 96 | } else { 97 | $export[] = " {$key} => " . var_export($val, true); 98 | } 99 | } 100 | return 'array (' . PHP_EOL . implode(PHP_EOL, $export) . PHP_EOL . ')'; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/CaughtException.php: -------------------------------------------------------------------------------- 1 | request = $request; 55 | $this->responder = $responder; 56 | } 57 | 58 | /** 59 | * 60 | * Invokes the action. 61 | * 62 | * @param Exception $exception The exception caught by the web kernel. 63 | * 64 | * @return null 65 | * 66 | */ 67 | public function __invoke(Exception $exception) 68 | { 69 | $this->responder->setData(array( 70 | 'exception' => $exception, 71 | 'method' => $this->request->method->get(), 72 | 'path' => $this->request->url->get(PHP_URL_PATH), 73 | 'params' => $this->request->params->get() 74 | )); 75 | $this->responder->__invoke(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/CaughtExceptionResponder.php: -------------------------------------------------------------------------------- 1 | data['exception']); 32 | $content = "Exception '{$class}' thrown for " 33 | . "{$this->data['method']} {$this->data['path']}" 34 | . PHP_EOL . PHP_EOL 35 | . "Params: " . $this->exportParams($this->data['params']) 36 | . PHP_EOL . PHP_EOL 37 | . (string) $this->data['exception'] 38 | . PHP_EOL; 39 | $this->response->status->set('500', 'Server Error'); 40 | $this->response->content->set($content); 41 | $this->response->content->setType('text/plain'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/MissingAction.php: -------------------------------------------------------------------------------- 1 | request = $request; 54 | $this->responder = $responder; 55 | } 56 | 57 | /** 58 | * 59 | * Invokes the action. 60 | * 61 | * @param string $missing_action The name of the missing action. 62 | * 63 | * @return null 64 | * 65 | */ 66 | public function __invoke($missing_action) 67 | { 68 | $this->responder->setData(array( 69 | 'missing_action' => $missing_action, 70 | 'method' => $this->request->method->get(), 71 | 'path' => $this->request->url->get(PHP_URL_PATH), 72 | 'params' => $this->request->params->get(), 73 | )); 74 | $this->responder->__invoke(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/MissingActionResponder.php: -------------------------------------------------------------------------------- 1 | data['missing_action']}' " 30 | . "for {$this->data['method']} {$this->data['path']}" 31 | . PHP_EOL . PHP_EOL 32 | . "Params: " . $this->exportParams($this->data['params']) 33 | . PHP_EOL; 34 | $this->response->status->set('404', 'Not Found'); 35 | $this->response->content->set($content); 36 | $this->response->content->setType('text/plain'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/MissingRoute.php: -------------------------------------------------------------------------------- 1 | request = $request; 54 | $this->responder = $responder; 55 | } 56 | 57 | /** 58 | * 59 | * Invokes the controller. 60 | * 61 | * @return null 62 | * 63 | */ 64 | public function __invoke() 65 | { 66 | $this->responder->setData(array( 67 | 'method' => $this->request->method->get(), 68 | 'path' => $this->request->url->get(PHP_URL_PATH), 69 | )); 70 | $this->responder->__invoke(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/MissingRouteResponder.php: -------------------------------------------------------------------------------- 1 | data['method']} {$this->data['path']}" 30 | . PHP_EOL; 31 | $this->response->status->set('404', 'Not Found'); 32 | $this->response->content->set($content); 33 | $this->response->content->setType('text/plain'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/WebKernel.php: -------------------------------------------------------------------------------- 1 | router = $router; 66 | $this->dispatcher = $dispatcher; 67 | $this->response_sender = $response_sender; 68 | } 69 | 70 | /** 71 | * 72 | * Magic get for read-only properties. 73 | * 74 | * @param string $key The property name. 75 | * 76 | * @return mixed The property. 77 | * 78 | */ 79 | public function __get($key) 80 | { 81 | return $this->$key; 82 | } 83 | 84 | /** 85 | * 86 | * Routes the request through the dispatcher and sends the response. 87 | * 88 | * @return null 89 | * 90 | */ 91 | public function __invoke() 92 | { 93 | $this->router->__invoke(); 94 | $this->dispatcher->__invoke(); 95 | $this->response_sender->__invoke(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/WebKernelDispatcher.php: -------------------------------------------------------------------------------- 1 | request = $request; 69 | $this->dispatcher = $dispatcher; 70 | $this->logger = $logger; 71 | } 72 | 73 | /** 74 | * 75 | * Dispatches the request. 76 | * 77 | * @return null 78 | * 79 | */ 80 | public function __invoke() 81 | { 82 | $object_param = $this->dispatcher->getObjectParam(); 83 | if (! $object_param) { 84 | $object_param = 'action'; 85 | } 86 | $action = $this->request->params->get($object_param); 87 | $this->logControllerValue($action); 88 | $this->checkForMissingController($action); 89 | try { 90 | $this->dispatcher->__invoke($this->request->params->get()); 91 | } catch (Exception $e) { 92 | $this->caughtException($e); 93 | } 94 | } 95 | 96 | /** 97 | * 98 | * Logs the action to be dispatched to. 99 | * 100 | * @param mixed $action The action to be dispatched to. 101 | * 102 | * @return null 103 | * 104 | */ 105 | protected function logControllerValue($action) 106 | { 107 | $message = __METHOD__ . ' to '; 108 | if (is_object($action)) { 109 | $message .= 'object'; 110 | } else { 111 | $message .= $action; 112 | } 113 | $this->logger->debug($message); 114 | } 115 | 116 | /** 117 | * 118 | * Check for a missing action. 119 | * 120 | * @param mixed $action The action to be dispatched to. 121 | * 122 | * @return null 123 | * 124 | */ 125 | protected function checkForMissingController($action) 126 | { 127 | $exists = is_object($action) 128 | || $this->dispatcher->hasObject($action); 129 | if ($exists) { 130 | return; 131 | } 132 | 133 | $this->logger->debug(__METHOD__ . " missing action '$action'"); 134 | $this->request->params['action'] = 'aura.web_kernel.missing_action'; 135 | $this->request->params['missing_action'] = $action; 136 | } 137 | 138 | /** 139 | * 140 | * Caught an exception while dispatching. 141 | * 142 | * @param Exception $e The caught exception. 143 | * 144 | * @return null 145 | * 146 | */ 147 | protected function caughtException(Exception $e) 148 | { 149 | $this->logger->debug(__CLASS__ . " caught exception " . get_class($e)); 150 | $this->dispatcher->__invoke(array( 151 | 'action' => 'aura.web_kernel.caught_exception', 152 | 'exception' => $e, 153 | )); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/WebKernelRouter.php: -------------------------------------------------------------------------------- 1 | request = $request; 68 | $this->router = $router; 69 | $this->logger = $logger; 70 | } 71 | 72 | /** 73 | * 74 | * Determines the route and inserts the route params into the request. 75 | * 76 | * @return null 77 | * 78 | */ 79 | public function __invoke() 80 | { 81 | $path = $this->getPath(); 82 | $route = $this->getRoute($path); 83 | if ($route) { 84 | $this->request->params->set($route->params); 85 | } else { 86 | $this->logger->debug(__CLASS__ . ' missing route ' . $path); 87 | $this->request->params['action'] = 'aura.web_kernel.missing_route'; 88 | } 89 | } 90 | 91 | /** 92 | * 93 | * Gets the path from the URL. 94 | * 95 | * @return string 96 | * 97 | */ 98 | protected function getPath() 99 | { 100 | $path = $this->request->url->get(PHP_URL_PATH); 101 | return $this->removeScriptFromPath($path); 102 | } 103 | 104 | /** 105 | * 106 | * Removes the bootstrap script (if any) from the URL path. 107 | * 108 | * @param string $path The URL path. 109 | * 110 | * @return string 111 | * 112 | */ 113 | protected function removeScriptFromPath($path) 114 | { 115 | $pos = strpos($path, '/index.php'); 116 | if ($pos !== false) { 117 | $path = substr($path, $pos + 10); 118 | $path = '/' . ltrim($path, '/'); 119 | } 120 | return $path; 121 | } 122 | 123 | /** 124 | * 125 | * Given a URL path, gets a matching route from the router. 126 | * 127 | * @param string $path The URL path. 128 | * 129 | * @return string 130 | * 131 | */ 132 | protected function getRoute($path) 133 | { 134 | $verb = $this->request->method->get(); 135 | $this->logger->debug(__CLASS__ . " $verb $path"); 136 | $route = $this->router->match($path, $this->request->server->get()); 137 | $this->logRoutesTried(); 138 | return $route; 139 | } 140 | 141 | /** 142 | * 143 | * Logs the different routes tried by the router. 144 | * 145 | * @return null 146 | * 147 | */ 148 | protected function logRoutesTried() 149 | { 150 | $verb = $this->request->method->get(); 151 | $routes = $this->router->getDebug(); 152 | foreach ($routes as $tried) { 153 | foreach ($tried->debug as $message) { 154 | $name = $tried->name 155 | ? $tried->name 156 | : $verb . ' ' . $tried->path; 157 | $message = __CLASS__ . " $name $message"; 158 | $this->logger->debug($message); 159 | } 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /tests/WebKernelTest.php: -------------------------------------------------------------------------------- 1 | newKernel( 20 | dirname(__DIR__), 21 | 'Aura\Web_Kernel\WebKernel', 22 | ContainerBuilder::DISABLE_AUTO_RESOLVE 23 | ); 24 | $web_kernel(); 25 | return $web_kernel; 26 | } 27 | 28 | public function testHelloWorld() 29 | { 30 | $_SERVER['REQUEST_METHOD'] = 'GET'; 31 | $_SERVER['REQUEST_URI'] = '/aura/web-kernel/integration/hello'; 32 | $web_kernel = $this->index(); 33 | 34 | $expect = 'Hello World!'; 35 | $actual = FakeResponseSender::$content; 36 | $this->assertSame($expect, $actual); 37 | } 38 | 39 | public function testHelloWorldViaIndexPhp() 40 | { 41 | $_SERVER['REQUEST_METHOD'] = 'GET'; 42 | $_SERVER['REQUEST_URI'] = '/index.php/aura/web-kernel/integration/hello'; 43 | $web_kernel = $this->index(); 44 | 45 | $expect = 'Hello World!'; 46 | $actual = FakeResponseSender::$content; 47 | $this->assertSame($expect, $actual); 48 | } 49 | 50 | public function testMissingRoute() 51 | { 52 | $_SERVER['REQUEST_METHOD'] = 'GET'; 53 | $_SERVER['REQUEST_URI'] = '/aura/web-kernel/integration/missing-route'; 54 | $web_kernel = $this->index(); 55 | 56 | $expect = 'No route for GET /aura/web-kernel/integration/missing-route'; 57 | $actual = trim(FakeResponseSender::$content); 58 | $this->assertSame($expect, $actual); 59 | } 60 | 61 | public function testMissingAction() 62 | { 63 | $_SERVER['REQUEST_METHOD'] = 'GET'; 64 | $_SERVER['REQUEST_URI'] = '/aura/web-kernel/integration/missing-action'; 65 | $web_kernel = $this->index(); 66 | 67 | $expect = << 'aura.web_kernel.missing_action' 72 | 'true' => true 73 | 'false' => false 74 | 'null' => NULL 75 | 'object' => Aura\Web_Kernel\_Config\WebKernelTest 76 | 'int' => 88 77 | 'float' => 12.34 78 | 'missing_action' => 'no-such-action' 79 | ) 80 | EXPECT; 81 | $actual = trim(FakeResponseSender::$content); 82 | $this->assertSame($expect, $actual); 83 | } 84 | 85 | public function testCaughtException() 86 | { 87 | $_SERVER['REQUEST_METHOD'] = 'GET'; 88 | $_SERVER['REQUEST_URI'] = '/aura/web-kernel/integration/throw-exception'; 89 | $web_kernel = $this->index(); 90 | 91 | $expect = "Exception 'Exception' thrown for GET /aura/web-kernel/integration/throw-exception"; 92 | $actual = explode(PHP_EOL, FakeResponseSender::$content); 93 | // only check the first line 94 | $this->assertSame($expect, $actual[0]); 95 | } 96 | } 97 | --------------------------------------------------------------------------------