* initial version
This commit is contained in:
commit
389e453a56
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/.phpcs-cache
|
||||
/.phpunit.result.cache
|
||||
/clover.xml
|
||||
/coveralls-upload.json
|
||||
/phpunit.xml
|
||||
/vendor/
|
||||
1
COPYRIGHT.md
Normal file
1
COPYRIGHT.md
Normal file
@ -0,0 +1 @@
|
||||
Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
|
||||
26
LICENSE.md
Normal file
26
LICENSE.md
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Laminas Foundation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
173
README.md
Normal file
173
README.md
Normal file
@ -0,0 +1,173 @@
|
||||
# Mezzio Skeleton and Installer
|
||||
|
||||
[](https://travis-ci.com/mezzio/mezzio-skeleton)
|
||||
[](https://coveralls.io/github/mezzio/mezzio-skeleton?branch=master)
|
||||
|
||||
*Begin developing PSR-15 middleware applications in seconds!*
|
||||
|
||||
[mezzio](https://github.com/mezzio/mezzio) builds on
|
||||
[laminas-stratigility](https://github.com/laminas/laminas-stratigility) to
|
||||
provide a minimalist PSR-15 middleware framework for PHP with routing, DI
|
||||
container, optional templating, and optional error handling capabilities.
|
||||
|
||||
This installer will setup a skeleton application based on mezzio by
|
||||
choosing optional packages based on user input as demonstrated in the following
|
||||
screenshot:
|
||||
|
||||

|
||||
|
||||
The user selected packages are saved into `composer.json` so that everyone else
|
||||
working on the project have the same packages installed. Configuration files and
|
||||
templates are prepared for first use. The installer command is removed from
|
||||
`composer.json` after setup succeeded, and all installer related files are
|
||||
removed.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Start your new Mezzio project with composer:
|
||||
|
||||
```bash
|
||||
$ composer create-project mezzio/mezzio-skeleton <project-path>
|
||||
```
|
||||
|
||||
After choosing and installing the packages you want, go to the
|
||||
`<project-path>` and start PHP's built-in web server to verify installation:
|
||||
|
||||
```bash
|
||||
$ composer run --timeout=0 serve
|
||||
```
|
||||
|
||||
You can then browse to http://localhost:8080.
|
||||
|
||||
> ### Linux users
|
||||
>
|
||||
> On PHP versions prior to 7.1.14 and 7.2.2, this command might not work as
|
||||
> expected due to a bug in PHP that only affects linux environments. In such
|
||||
> scenarios, you will need to start the [built-in web
|
||||
> server](http://php.net/manual/en/features.commandline.webserver.php) yourself,
|
||||
> using the following command:
|
||||
>
|
||||
> ```bash
|
||||
> $ php -S 0.0.0.0:8080 -t public/ public/index.php
|
||||
> ```
|
||||
|
||||
> ### Setting a timeout
|
||||
>
|
||||
> Composer commands time out after 300 seconds (5 minutes). On Linux-based
|
||||
> systems, the `php -S` command that `composer serve` spawns continues running
|
||||
> as a background process, but on other systems halts when the timeout occurs.
|
||||
>
|
||||
> As such, we recommend running the `serve` script using a timeout. This can
|
||||
> be done by using `composer run` to execute the `serve` script, with a
|
||||
> `--timeout` option. When set to `0`, as in the previous example, no timeout
|
||||
> will be used, and it will run until you cancel the process (usually via
|
||||
> `Ctrl-C`). Alternately, you can specify a finite timeout; as an example,
|
||||
> the following will extend the timeout to a full day:
|
||||
>
|
||||
> ```bash
|
||||
> $ composer run --timeout=86400 serve
|
||||
> ```
|
||||
|
||||
## Installing alternative packages
|
||||
|
||||
There is a feature to install alternative packages: Instead of entering one of
|
||||
the selection **you can actually type the package name and version**.
|
||||
|
||||
> ```
|
||||
> Which template engine do you want to use?
|
||||
> [1] Plates
|
||||
> [2] Twig
|
||||
> [3] zend-view installs zend-servicemanager
|
||||
> [n] None of the above
|
||||
> Make your selection or type a composer package name and version (n): infw/pug:0.1
|
||||
> - Searching for infw/pug:0.1
|
||||
> - Adding package infw/pug (0.1)
|
||||
> ```
|
||||
|
||||
That feature allows you to install any alternative package you want. It has its limitations though:
|
||||
|
||||
* The alternative package must follow this format `namespace/package:1.0`. It needs the correct version.
|
||||
* Templates are not copied, but the ConfigProvider can be configured in such way that it uses the
|
||||
default templates directly from the package itself.
|
||||
* This doesn't work for containers as the container.php file needs to be copied.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the installer fails during the ``composer create-project`` phase, please go
|
||||
through the following list before opening a new issue. Most issues we have seen
|
||||
so far can be solved by `self-update` and `clear-cache`.
|
||||
|
||||
1. Be sure to work with the latest version of composer by running `composer self-update`.
|
||||
2. Try clearing Composer's cache by running `composer clear-cache`.
|
||||
|
||||
If neither of the above help, you might face more serious issues:
|
||||
|
||||
- Info about the [zlib_decode error](https://github.com/composer/composer/issues/4121).
|
||||
- Info and solutions for [composer degraded mode](https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode).
|
||||
|
||||
## Application Development Mode Tool
|
||||
|
||||
This skeleton comes with [laminas-development-mode](https://github.com/laminas/laminas-development-mode).
|
||||
It provides a composer script to allow you to enable and disable development mode.
|
||||
|
||||
### To enable development mode
|
||||
|
||||
**Note:** Do NOT run development mode on your production server!
|
||||
|
||||
```bash
|
||||
$ composer development-enable
|
||||
```
|
||||
|
||||
**Note:** Enabling development mode will also clear your configuration cache, to
|
||||
allow safely updating dependencies and ensuring any new configuration is picked
|
||||
up by your application.
|
||||
|
||||
### To disable development mode
|
||||
|
||||
```bash
|
||||
$ composer development-disable
|
||||
```
|
||||
|
||||
### Development mode status
|
||||
|
||||
```bash
|
||||
$ composer development-status
|
||||
```
|
||||
|
||||
## Configuration caching
|
||||
|
||||
By default, the skeleton will create a configuration cache in
|
||||
`data/config-cache.php`. When in development mode, the configuration cache is
|
||||
disabled, and switching in and out of development mode will remove the
|
||||
configuration cache.
|
||||
|
||||
You may need to clear the configuration cache in production when deploying if
|
||||
you deploy to the same directory. You may do so using the following:
|
||||
|
||||
```bash
|
||||
$ composer clear-config-cache
|
||||
```
|
||||
|
||||
You may also change the location of the configuration cache itself by editing
|
||||
the `config/config.php` file and changing the `config_cache_path` entry of the
|
||||
local `$cacheConfig` variable.
|
||||
|
||||
## Skeleton Development
|
||||
|
||||
This section applies only if you cloned this repo with `git clone`, not when you
|
||||
installed mezzio with `composer create-project ...`.
|
||||
|
||||
If you want to run tests against the installer, you need to clone this repo and
|
||||
setup all dependencies with composer. Make sure you **prevent composer running
|
||||
scripts** with `--no-scripts`, otherwise it will remove the installer and all
|
||||
tests.
|
||||
|
||||
```bash
|
||||
$ composer update --no-scripts
|
||||
$ composer test
|
||||
```
|
||||
|
||||
Please note that the installer tests remove installed config files and templates
|
||||
before and after running the tests.
|
||||
|
||||
Before contributing read [the contributing guide](https://github.com/mezzio/.github/blob/master/CONTRIBUTING.md).
|
||||
45
bin/clear-config-cache.php
Normal file
45
bin/clear-config-cache.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @see https://github.com/mezzio/mezzio-skeleton for the canonical source repository
|
||||
* @copyright https://github.com/mezzio/mezzio-skeleton/blob/master/COPYRIGHT.md
|
||||
* @license https://github.com/mezzio/mezzio-skeleton/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
chdir(__DIR__ . '/../');
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$config = include 'config/config.php';
|
||||
|
||||
if (! isset($config['config_cache_path'])) {
|
||||
echo "No configuration cache path found" . PHP_EOL;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (! file_exists($config['config_cache_path'])) {
|
||||
printf(
|
||||
"Configured config cache file '%s' not found%s",
|
||||
$config['config_cache_path'],
|
||||
PHP_EOL
|
||||
);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (false === unlink($config['config_cache_path'])) {
|
||||
printf(
|
||||
"Error removing config cache file '%s'%s",
|
||||
$config['config_cache_path'],
|
||||
PHP_EOL
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf(
|
||||
"Removed configured config cache file '%s'%s",
|
||||
$config['config_cache_path'],
|
||||
PHP_EOL
|
||||
);
|
||||
exit(0);
|
||||
95
composer.json
Normal file
95
composer.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "yvan/mezzio-api-skeleton",
|
||||
"description": "Laminas mezzio skeleton. Begin developing PSR-15 middleware applications in seconds!",
|
||||
"type": "project",
|
||||
"license": "BSD-3-Clause",
|
||||
"keywords": [
|
||||
"laminas",
|
||||
"mezzio",
|
||||
"skeleton",
|
||||
"middleware",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"psr-11",
|
||||
"psr-15"
|
||||
],
|
||||
"homepage": "https://mezzio.dev",
|
||||
"support": {
|
||||
"docs": "https://docs.mezzio.dev/mezzio/",
|
||||
"issues": "https://github.com/mezzio/mezzio-skeleton/issues",
|
||||
"source": "https://github.com/mezzio/mezzio-skeleton",
|
||||
"rss": "https://github.com/mezzio/mezzio-skeleton/releases.atom",
|
||||
"chat": "https://laminas.dev/chat",
|
||||
"forum": "https://discourse.laminas.dev"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"laminas": {
|
||||
"component-whitelist": [
|
||||
"mezzio/mezzio",
|
||||
"mezzio/mezzio-helpers",
|
||||
"mezzio/mezzio-router",
|
||||
"laminas/laminas-httphandlerrunner",
|
||||
"mezzio/mezzio-fastroute"
|
||||
]
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"ext-json": "*",
|
||||
"composer/package-versions-deprecated": "^1.10.99",
|
||||
"laminas/laminas-component-installer": "^2.1.2",
|
||||
"laminas/laminas-config-aggregator": "^1.2",
|
||||
"laminas/laminas-diactoros": "^2.3.0",
|
||||
"laminas/laminas-servicemanager": "^3.4",
|
||||
"laminas/laminas-stdlib": "^3.2.1",
|
||||
"laminas/laminas-zendframework-bridge": "^1.0",
|
||||
"los/loslog": "^3.3",
|
||||
"mezzio/mezzio": "^3.2.1",
|
||||
"mezzio/mezzio-fastroute": "^3.0.3",
|
||||
"mezzio/mezzio-helpers": "^5.3",
|
||||
"roave/psr-container-doctrine": "^2.2",
|
||||
"tuupola/cors-middleware": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"laminas/laminas-development-mode": "^3.2",
|
||||
"mezzio/mezzio-tooling": "^1.3",
|
||||
"phpspec/prophecy": "^1.10.3",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.3.7",
|
||||
"roave/security-advisories": "dev-master",
|
||||
"filp/whoops": "^2.7.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/App/",
|
||||
"ApiLibs\\": "src/ApiLibs/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"AppTest\\": "test/AppTest/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-create-project-cmd": [
|
||||
"@development-enable"
|
||||
],
|
||||
"development-disable": "laminas-development-mode disable",
|
||||
"development-enable": "laminas-development-mode enable",
|
||||
"development-status": "laminas-development-mode status",
|
||||
"mezzio": "mezzio --ansi",
|
||||
"check": [
|
||||
"@cs-check",
|
||||
"@test"
|
||||
],
|
||||
"clear-config-cache": "php bin/clear-config-cache.php",
|
||||
"cs-check": "phpcs",
|
||||
"cs-fix": "phpcbf",
|
||||
"serve": "php -S 0.0.0.0:8080 -t public/",
|
||||
"test": "phpunit --colors=always",
|
||||
"test-coverage": "phpunit --colors=always --coverage-clover clover.xml"
|
||||
}
|
||||
}
|
||||
7050
composer.lock
generated
Normal file
7050
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
config/.gitignore
vendored
Normal file
1
config/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
development.config.php
|
||||
2
config/autoload/.gitignore
vendored
Normal file
2
config/autoload/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
local.php
|
||||
*.local.php
|
||||
26
config/autoload/dependencies.global.php
Normal file
26
config/autoload/dependencies.global.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
// Provides application-wide services.
|
||||
// We recommend using fully-qualified class names whenever possible as
|
||||
// service names.
|
||||
'dependencies' => [
|
||||
// Use 'aliases' to alias a service name to another service. The
|
||||
// key is the alias name, the value is the service to which it points.
|
||||
'aliases' => [
|
||||
// Fully\Qualified\ClassOrInterfaceName::class => Fully\Qualified\ClassName::class,
|
||||
],
|
||||
// Use 'invokables' for constructor-less services, or services that do
|
||||
// not require arguments to the constructor. Map a service name to the
|
||||
// class name.
|
||||
'invokables' => [
|
||||
// Fully\Qualified\InterfaceName::class => Fully\Qualified\ClassName::class,
|
||||
],
|
||||
// Use 'factories' for services provided by callbacks/factory classes.
|
||||
'factories' => [
|
||||
// Fully\Qualified\ClassName::class => Fully\Qualified\FactoryName::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
33
config/autoload/development.local.php.dist
Normal file
33
config/autoload/development.local.php.dist
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Development-only configuration.
|
||||
*
|
||||
* Put settings you want enabled when under development mode in this file, and
|
||||
* check it into your repository.
|
||||
*
|
||||
* Developers on your team will then automatically enable them by calling on
|
||||
* `composer development-enable`.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Mezzio\Container;
|
||||
use Mezzio\Middleware\ErrorResponseGenerator;
|
||||
|
||||
return [
|
||||
'dependencies' => [
|
||||
'factories' => [
|
||||
ErrorResponseGenerator::class => Container\WhoopsErrorResponseGeneratorFactory::class,
|
||||
'Mezzio\Whoops' => Container\WhoopsFactory::class,
|
||||
'Mezzio\WhoopsPageHandler' => Container\WhoopsPageHandlerFactory::class,
|
||||
],
|
||||
],
|
||||
'whoops' => [
|
||||
'json_exceptions' => [
|
||||
'display' => true,
|
||||
'show_trace' => true,
|
||||
'ajax_only' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
13
config/autoload/local.php.dist
Normal file
13
config/autoload/local.php.dist
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Local configuration.
|
||||
*
|
||||
* Copy this file to `local.php` and change its settings as required.
|
||||
* `local.php` is ignored by git and safe to use for local and sensitive data like usernames and passwords.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
];
|
||||
25
config/autoload/mezzio.global.php
Normal file
25
config/autoload/mezzio.global.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ConfigAggregator\ConfigAggregator;
|
||||
|
||||
return [
|
||||
// Toggle the configuration cache. Set this to boolean false, or remove the
|
||||
// directive, to disable configuration caching. Toggling development mode
|
||||
// will also disable it by default; clear the configuration cache using
|
||||
// `composer clear-config-cache`.
|
||||
ConfigAggregator::ENABLE_CACHE => true,
|
||||
|
||||
// Enable debugging; typically used to provide debugging information within templates.
|
||||
'debug' => false,
|
||||
|
||||
'mezzio' => [
|
||||
// Provide templates for the error handling middleware to use when
|
||||
// generating responses.
|
||||
'error_handler' => [
|
||||
'template_404' => 'error::404',
|
||||
'template_error' => 'error::error',
|
||||
],
|
||||
],
|
||||
];
|
||||
47
config/config.php
Normal file
47
config/config.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ConfigAggregator\ArrayProvider;
|
||||
use Laminas\ConfigAggregator\ConfigAggregator;
|
||||
use Laminas\ConfigAggregator\PhpFileProvider;
|
||||
|
||||
// To enable or disable caching, set the `ConfigAggregator::ENABLE_CACHE` boolean in
|
||||
// `config/autoload/local.php`.
|
||||
$cacheConfig = [
|
||||
'config_cache_path' => 'data/cache/config-cache.php',
|
||||
];
|
||||
|
||||
$aggregator = new ConfigAggregator([
|
||||
\Laminas\Log\ConfigProvider::class,
|
||||
\Mezzio\Router\FastRouteRouter\ConfigProvider::class,
|
||||
\Laminas\HttpHandlerRunner\ConfigProvider::class,
|
||||
// Include cache configuration
|
||||
new ArrayProvider($cacheConfig),
|
||||
|
||||
\Mezzio\Helper\ConfigProvider::class,
|
||||
\Mezzio\ConfigProvider::class,
|
||||
\Mezzio\Router\ConfigProvider::class,
|
||||
\Laminas\Diactoros\ConfigProvider::class,
|
||||
|
||||
// Swoole config to overwrite some services (if installed)
|
||||
class_exists(\Mezzio\Swoole\ConfigProvider::class)
|
||||
? \Mezzio\Swoole\ConfigProvider::class
|
||||
: function(): array { return[]; },
|
||||
|
||||
// Default App module config
|
||||
App\ConfigProvider::class,
|
||||
|
||||
// Load application config in a pre-defined order in such a way that local settings
|
||||
// overwrite global settings. (Loaded as first to last):
|
||||
// - `global.php`
|
||||
// - `*.global.php`
|
||||
// - `local.php`
|
||||
// - `*.local.php`
|
||||
new PhpFileProvider(realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php'),
|
||||
|
||||
// Load development config if it exists
|
||||
new PhpFileProvider(realpath(__DIR__) . '/development.config.php'),
|
||||
], $cacheConfig['config_cache_path']);
|
||||
|
||||
return $aggregator->getMergedConfig();
|
||||
14
config/container.php
Normal file
14
config/container.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ServiceManager\ServiceManager;
|
||||
|
||||
// Load configuration
|
||||
$config = require __DIR__ . '/config.php';
|
||||
|
||||
$dependencies = $config['dependencies'];
|
||||
$dependencies['services']['config'] = $config;
|
||||
|
||||
// Build container
|
||||
return new ServiceManager($dependencies);
|
||||
31
config/development.config.php.dist
Normal file
31
config/development.config.php.dist
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* File required to allow enablement of development mode.
|
||||
*
|
||||
* For use with the laminas-development-mode tool.
|
||||
*
|
||||
* Usage:
|
||||
* $ composer development-disable
|
||||
* $ composer development-enable
|
||||
* $ composer development-status
|
||||
*
|
||||
* DO NOT MODIFY THIS FILE.
|
||||
*
|
||||
* Provide your own development-mode settings by editing the file
|
||||
* `config/autoload/development.local.php.dist`.
|
||||
*
|
||||
* Because this file is aggregated last, it simply ensures:
|
||||
*
|
||||
* - The `debug` flag is _enabled_.
|
||||
* - Configuration caching is _disabled_.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ConfigAggregator\ConfigAggregator;
|
||||
|
||||
return [
|
||||
'debug' => true,
|
||||
ConfigAggregator::ENABLE_CACHE => false,
|
||||
];
|
||||
76
config/pipeline.php
Normal file
76
config/pipeline.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\Stratigility\Middleware\ErrorHandler;
|
||||
use Mezzio\Application;
|
||||
use Mezzio\Handler\NotFoundHandler;
|
||||
use Mezzio\Helper\ServerUrlMiddleware;
|
||||
use Mezzio\Helper\UrlHelperMiddleware;
|
||||
use Mezzio\MiddlewareFactory;
|
||||
use Mezzio\Router\Middleware\DispatchMiddleware;
|
||||
use Mezzio\Router\Middleware\ImplicitHeadMiddleware;
|
||||
use Mezzio\Router\Middleware\ImplicitOptionsMiddleware;
|
||||
use Mezzio\Router\Middleware\MethodNotAllowedMiddleware;
|
||||
use Mezzio\Router\Middleware\RouteMiddleware;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Setup middleware pipeline:
|
||||
*/
|
||||
return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container) : void {
|
||||
// The error handler should be the first (most outer) middleware to catch
|
||||
// all Exceptions.
|
||||
$app->pipe(ErrorHandler::class);
|
||||
$app->pipe(ServerUrlMiddleware::class);
|
||||
|
||||
// Pipe more middleware here that you want to execute on every request:
|
||||
// - bootstrapping
|
||||
// - pre-conditions
|
||||
// - modifications to outgoing responses
|
||||
//
|
||||
// Piped Middleware may be either callables or service names. Middleware may
|
||||
// also be passed as an array; each item in the array must resolve to
|
||||
// middleware eventually (i.e., callable or service name).
|
||||
//
|
||||
// Middleware can be attached to specific paths, allowing you to mix and match
|
||||
// applications under a common domain. The handlers in each middleware
|
||||
// attached this way will see a URI with the matched path segment removed.
|
||||
//
|
||||
// i.e., path of "/api/member/profile" only passes "/member/profile" to $apiMiddleware
|
||||
// - $app->pipe('/api', $apiMiddleware);
|
||||
// - $app->pipe('/docs', $apiDocMiddleware);
|
||||
// - $app->pipe('/files', $filesMiddleware);
|
||||
|
||||
// Register the routing middleware in the middleware pipeline.
|
||||
// This middleware registers the Mezzio\Router\RouteResult request attribute.
|
||||
$app->pipe(RouteMiddleware::class);
|
||||
|
||||
// The following handle routing failures for common conditions:
|
||||
// - HEAD request but no routes answer that method
|
||||
// - OPTIONS request but no routes answer that method
|
||||
// - method not allowed
|
||||
// Order here matters; the MethodNotAllowedMiddleware should be placed
|
||||
// after the Implicit*Middleware.
|
||||
$app->pipe(ImplicitHeadMiddleware::class);
|
||||
$app->pipe(ImplicitOptionsMiddleware::class);
|
||||
$app->pipe(MethodNotAllowedMiddleware::class);
|
||||
|
||||
// Seed the UrlHelper with the routing results:
|
||||
$app->pipe(UrlHelperMiddleware::class);
|
||||
|
||||
// Add more middleware here that needs to introspect the routing results; this
|
||||
// might include:
|
||||
//
|
||||
// - route-based authentication
|
||||
// - route-based validation
|
||||
// - etc.
|
||||
|
||||
// Register the dispatch middleware in the middleware pipeline
|
||||
$app->pipe(DispatchMiddleware::class);
|
||||
|
||||
// At this point, if no Response is returned by any middleware, the
|
||||
// NotFoundHandler kicks in; alternately, you can provide other fallback
|
||||
// middleware to execute.
|
||||
$app->pipe(NotFoundHandler::class);
|
||||
};
|
||||
42
config/routes.php
Normal file
42
config/routes.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Mezzio\Application;
|
||||
use Mezzio\MiddlewareFactory;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* FastRoute route configuration
|
||||
*
|
||||
* @see https://github.com/nikic/FastRoute
|
||||
*
|
||||
* Setup routes with a single request method:
|
||||
*
|
||||
* $app->get('/', App\Handler\HomePageHandler::class, 'home');
|
||||
* $app->post('/album', App\Handler\AlbumCreateHandler::class, 'album.create');
|
||||
* $app->put('/album/{id:\d+}', App\Handler\AlbumUpdateHandler::class, 'album.put');
|
||||
* $app->patch('/album/{id:\d+}', App\Handler\AlbumUpdateHandler::class, 'album.patch');
|
||||
* $app->delete('/album/{id:\d+}', App\Handler\AlbumDeleteHandler::class, 'album.delete');
|
||||
*
|
||||
* Or with multiple request methods:
|
||||
*
|
||||
* $app->route('/contact', App\Handler\ContactHandler::class, ['GET', 'POST', ...], 'contact');
|
||||
*
|
||||
* Or handling all request methods:
|
||||
*
|
||||
* $app->route('/contact', App\Handler\ContactHandler::class)->setName('contact');
|
||||
*
|
||||
* or:
|
||||
*
|
||||
* $app->route(
|
||||
* '/contact',
|
||||
* App\Handler\ContactHandler::class,
|
||||
* Mezzio\Router\Route::HTTP_METHOD_ANY,
|
||||
* 'contact'
|
||||
* );
|
||||
*/
|
||||
return static function (Application $app, MiddlewareFactory $factory, ContainerInterface $container): void {
|
||||
$app->get('/', App\Handler\HomePageHandler::class, 'home');
|
||||
$app->get('/api/ping', App\Handler\PingHandler::class, 'api.ping');
|
||||
};
|
||||
4
data/.gitignore
vendored
Normal file
4
data/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!cache
|
||||
!cache/.gitkeep
|
||||
!.gitignore
|
||||
0
data/cache/.gitkeep
vendored
Normal file
0
data/cache/.gitkeep
vendored
Normal file
21
phpcs.xml.dist
Normal file
21
phpcs.xml.dist
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
|
||||
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="cache" value=".phpcs-cache"/>
|
||||
<arg name="colors"/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="parallel" value="80"/>
|
||||
|
||||
<!-- Show progress -->
|
||||
<arg value="p"/>
|
||||
|
||||
<!-- Paths to check -->
|
||||
<file>config</file>
|
||||
<file>src</file>
|
||||
<file>test</file>
|
||||
|
||||
<!-- Include all rules from the Laminas Coding Standard -->
|
||||
<rule ref="LaminasCodingStandard"/>
|
||||
</ruleset>
|
||||
13
phpunit.xml.dist
Normal file
13
phpunit.xml.dist
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true">
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="App\\Tests">
|
||||
<directory>./test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
19
public/.htaccess
Normal file
19
public/.htaccess
Normal file
@ -0,0 +1,19 @@
|
||||
RewriteEngine On
|
||||
# The following rule allows authentication to work with fast-cgi
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
# The following rule tells Apache that if the requested filename
|
||||
# exists, simply serve it.
|
||||
RewriteCond %{REQUEST_FILENAME} -s [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -l [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^.*$ - [NC,L]
|
||||
|
||||
# The following rewrites all other queries to index.php. The
|
||||
# condition ensures that if you are using Apache aliases to do
|
||||
# mass virtual hosting, the base path will be prepended to
|
||||
# allow proper resolution of the index.php file; it will work
|
||||
# in non-aliased environments as well, providing a safe, one-size
|
||||
# fits all solution.
|
||||
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
|
||||
RewriteRule ^(.*) - [E=BASE:%1]
|
||||
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
|
||||
30
public/index.php
Normal file
30
public/index.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// Delegate static file requests back to the PHP built-in webserver
|
||||
if (PHP_SAPI === 'cli-server' && $_SERVER['SCRIPT_FILENAME'] !== __FILE__) {
|
||||
return false;
|
||||
}
|
||||
|
||||
chdir(dirname(__DIR__));
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* Self-called anonymous function that creates its own scope and keeps the global namespace clean.
|
||||
*/
|
||||
(function () {
|
||||
/** @var \Psr\Container\ContainerInterface $container */
|
||||
$container = require 'config/container.php';
|
||||
|
||||
/** @var \Mezzio\Application $app */
|
||||
$app = $container->get(\Mezzio\Application::class);
|
||||
$factory = $container->get(\Mezzio\MiddlewareFactory::class);
|
||||
|
||||
// Execute programmatic/declarative middleware pipeline and routing
|
||||
// configuration statements
|
||||
(require 'config/pipeline.php')($app, $factory, $container);
|
||||
(require 'config/routes.php')($app, $factory, $container);
|
||||
|
||||
$app->run();
|
||||
})();
|
||||
166
src/ApiLibs/AbstractHandler/CrudHandler.php
Normal file
166
src/ApiLibs/AbstractHandler/CrudHandler.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ApiLibs\AbstractHandler;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Laminas\Json\Json;
|
||||
|
||||
abstract class CrudHandler implements RequestHandlerInterface
|
||||
{
|
||||
const IDENTIFIER_NAME = 'id';
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$requestMethod = strtoupper($request->getMethod());
|
||||
$id = $request->getAttribute(static::IDENTIFIER_NAME);
|
||||
|
||||
switch ($requestMethod) {
|
||||
case 'GET':
|
||||
return isset($id)
|
||||
? $this->get($request)
|
||||
: $this->getList($request);
|
||||
case 'POST':
|
||||
return $this->create($request);
|
||||
case 'PUT':
|
||||
return $this->update($request);
|
||||
case 'DELETE':
|
||||
return isset($id)
|
||||
? $this->delete($request)
|
||||
: $this->deleteList($request);
|
||||
case 'HEAD':
|
||||
return $this->head($request);
|
||||
case 'OPTIONS':
|
||||
return $this->options($request);
|
||||
case 'PATCH':
|
||||
return $this->patch($request);
|
||||
default:
|
||||
return $this->notAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
public function get(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function getList(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function create(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function update(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function delete(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function deleteList(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function head(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
public function options(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return new EmptyResponse(200);
|
||||
}
|
||||
|
||||
public function patch(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return $this->notAllowed();
|
||||
}
|
||||
|
||||
final public function notAllowed(): ResponseInterface
|
||||
{
|
||||
return $this->createResponse(['content' => 'Method not allowed'], 405);
|
||||
}
|
||||
|
||||
final protected function createResponse($data, $status = 200): ResponseInterface
|
||||
{
|
||||
return new JsonResponse($data, $status);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return array|object
|
||||
*/
|
||||
public function getRequestData(ServerRequestInterface $request)
|
||||
{
|
||||
$body = $request->getParsedBody();
|
||||
|
||||
if (!empty($body)) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
return $this->parseRequestData(
|
||||
$request->getBody()->getContents(),
|
||||
$request->getHeaderLine('content-type')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $input
|
||||
* @param string $contentType
|
||||
* @return mixed
|
||||
*/
|
||||
private function parseRequestData($input, $contentType)
|
||||
{
|
||||
$contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
|
||||
$parser = $this->returnParserContentType($contentTypeParts[0]);
|
||||
|
||||
return $parser($input);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $contentType
|
||||
* @return callable
|
||||
*/
|
||||
private function returnParserContentType(string $contentType): callable
|
||||
{
|
||||
if ($contentType === 'application/x-www-form-urlencoded') {
|
||||
return function ($input) {
|
||||
parse_str($input, $data);
|
||||
return $data;
|
||||
};
|
||||
} elseif ($contentType === 'application/json') {
|
||||
return function ($input) {
|
||||
$jsonDecoder = new Json();
|
||||
try {
|
||||
return $jsonDecoder->decode($input, Json::TYPE_ARRAY);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} elseif ($contentType === 'multipart/form-data') {
|
||||
return function ($input) {
|
||||
return $input;
|
||||
};
|
||||
}
|
||||
|
||||
return function ($input) {
|
||||
return $input;
|
||||
};
|
||||
}
|
||||
}
|
||||
43
src/ApiLibs/ConfigProvider.php
Normal file
43
src/ApiLibs/ConfigProvider.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ApiLibs;
|
||||
|
||||
/**
|
||||
* The configuration provider for the App module
|
||||
*
|
||||
* @see https://docs.zendframework.com/zend-component-installer/
|
||||
*/
|
||||
class ConfigProvider
|
||||
{
|
||||
/**
|
||||
* Returns the configuration array
|
||||
*
|
||||
* To add a bit of a structure, each section is defined in a separate
|
||||
* method which returns an array with its configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __invoke()
|
||||
{
|
||||
return [
|
||||
'dependencies' => $this->getDependencies(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the container dependencies
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDependencies()
|
||||
{
|
||||
return [
|
||||
'invokables' => [],
|
||||
'factories' => [
|
||||
\Tuupola\Middleware\CorsMiddleware::class => Middleware\CorsMiddlewareFactory::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
23
src/ApiLibs/Middleware/CorsMiddlewareFactory.php
Normal file
23
src/ApiLibs/Middleware/CorsMiddlewareFactory.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ApiLibs\Middleware;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Tuupola\Middleware\CorsMiddleware;
|
||||
|
||||
class CorsMiddlewareFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): CorsMiddleware
|
||||
{
|
||||
return new CorsMiddleware([
|
||||
"headers.allow" => [
|
||||
"Authorization",
|
||||
"If-Match",
|
||||
"If-Unmodified-Since",
|
||||
"Content-type",
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
56
src/App/ConfigProvider.php
Normal file
56
src/App/ConfigProvider.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
/**
|
||||
* The configuration provider for the App module
|
||||
*
|
||||
* @see https://docs.laminas.dev/laminas-component-installer/
|
||||
*/
|
||||
class ConfigProvider
|
||||
{
|
||||
/**
|
||||
* Returns the configuration array
|
||||
*
|
||||
* To add a bit of a structure, each section is defined in a separate
|
||||
* method which returns an array with its configuration.
|
||||
*/
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => $this->getDependencies(),
|
||||
'templates' => $this->getTemplates(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the container dependencies
|
||||
*/
|
||||
public function getDependencies(): array
|
||||
{
|
||||
return [
|
||||
'invokables' => [
|
||||
Handler\PingHandler::class => Handler\PingHandler::class,
|
||||
],
|
||||
'factories' => [
|
||||
Handler\HomePageHandler::class => Handler\HomePageHandlerFactory::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the templates configuration
|
||||
*/
|
||||
public function getTemplates(): array
|
||||
{
|
||||
return [
|
||||
'paths' => [
|
||||
'app' => ['templates/app'],
|
||||
'error' => ['templates/error'],
|
||||
'layout' => ['templates/layout'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
106
src/App/Handler/HomePageHandler.php
Normal file
106
src/App/Handler/HomePageHandler.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Handler;
|
||||
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Mezzio\LaminasView\LaminasViewRenderer;
|
||||
use Mezzio\Plates\PlatesRenderer;
|
||||
use Mezzio\Router;
|
||||
use Mezzio\Template\TemplateRendererInterface;
|
||||
use Mezzio\Twig\TwigRenderer;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class HomePageHandler implements RequestHandlerInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $containerName;
|
||||
|
||||
/** @var Router\RouterInterface */
|
||||
private $router;
|
||||
|
||||
/** @var null|TemplateRendererInterface */
|
||||
private $template;
|
||||
|
||||
public function __construct(
|
||||
string $containerName,
|
||||
Router\RouterInterface $router,
|
||||
?TemplateRendererInterface $template = null
|
||||
) {
|
||||
$this->containerName = $containerName;
|
||||
$this->router = $router;
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$data = [];
|
||||
|
||||
switch ($this->containerName) {
|
||||
case 'Aura\Di\Container':
|
||||
$data['containerName'] = 'Aura.Di';
|
||||
$data['containerDocs'] = 'http://auraphp.com/packages/4.x/Di/';
|
||||
break;
|
||||
case 'Pimple\Psr11\Container':
|
||||
$data['containerName'] = 'Pimple';
|
||||
$data['containerDocs'] = 'https://pimple.symfony.com/';
|
||||
break;
|
||||
case 'Laminas\ServiceManager\ServiceManager':
|
||||
$data['containerName'] = 'Laminas Servicemanager';
|
||||
$data['containerDocs'] = 'https://docs.laminas.dev/laminas-servicemanager/';
|
||||
break;
|
||||
case 'Northwoods\Container\InjectorContainer':
|
||||
$data['containerName'] = 'Auryn';
|
||||
$data['containerDocs'] = 'https://github.com/rdlowrey/Auryn';
|
||||
break;
|
||||
case 'Symfony\Component\DependencyInjection\ContainerBuilder':
|
||||
$data['containerName'] = 'Symfony DI Container';
|
||||
$data['containerDocs'] = 'https://symfony.com/doc/current/service_container.html';
|
||||
break;
|
||||
case 'Elie\PHPDI\Config\ContainerWrapper':
|
||||
case 'DI\Container':
|
||||
$data['containerName'] = 'PHP-DI';
|
||||
$data['containerDocs'] = 'http://php-di.org';
|
||||
break;
|
||||
case 'Chubbyphp\Container\Container':
|
||||
$data['containerName'] = 'Chubbyphp Container';
|
||||
$data['containerDocs'] = 'https://github.com/chubbyphp/chubbyphp-container';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->router instanceof Router\AuraRouter) {
|
||||
$data['routerName'] = 'Aura.Router';
|
||||
$data['routerDocs'] = 'http://auraphp.com/packages/3.x/Router/';
|
||||
} elseif ($this->router instanceof Router\FastRouteRouter) {
|
||||
$data['routerName'] = 'FastRoute';
|
||||
$data['routerDocs'] = 'https://github.com/nikic/FastRoute';
|
||||
} elseif ($this->router instanceof Router\LaminasRouter) {
|
||||
$data['routerName'] = 'Laminas Router';
|
||||
$data['routerDocs'] = 'https://docs.laminas.dev/laminas-router/';
|
||||
}
|
||||
|
||||
if ($this->template === null) {
|
||||
return new JsonResponse([
|
||||
'welcome' => 'Congratulations! You have installed the mezzio skeleton application.',
|
||||
'docsUrl' => 'https://docs.mezzio.dev/mezzio/',
|
||||
] + $data);
|
||||
}
|
||||
|
||||
if ($this->template instanceof PlatesRenderer) {
|
||||
$data['templateName'] = 'Plates';
|
||||
$data['templateDocs'] = 'http://platesphp.com/';
|
||||
} elseif ($this->template instanceof TwigRenderer) {
|
||||
$data['templateName'] = 'Twig';
|
||||
$data['templateDocs'] = 'http://twig.sensiolabs.org/documentation';
|
||||
} elseif ($this->template instanceof LaminasViewRenderer) {
|
||||
$data['templateName'] = 'Laminas View';
|
||||
$data['templateDocs'] = 'https://docs.laminas.dev/laminas-view/';
|
||||
}
|
||||
|
||||
return new HtmlResponse($this->template->render('app::home-page', $data));
|
||||
}
|
||||
}
|
||||
25
src/App/Handler/HomePageHandlerFactory.php
Normal file
25
src/App/Handler/HomePageHandlerFactory.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Handler;
|
||||
|
||||
use Mezzio\Router\RouterInterface;
|
||||
use Mezzio\Template\TemplateRendererInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
use function get_class;
|
||||
|
||||
class HomePageHandlerFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container): RequestHandlerInterface
|
||||
{
|
||||
$router = $container->get(RouterInterface::class);
|
||||
$template = $container->has(TemplateRendererInterface::class)
|
||||
? $container->get(TemplateRendererInterface::class)
|
||||
: null;
|
||||
|
||||
return new HomePageHandler(get_class($container), $router, $template);
|
||||
}
|
||||
}
|
||||
20
src/App/Handler/PingHandler.php
Normal file
20
src/App/Handler/PingHandler.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Handler;
|
||||
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
use function time;
|
||||
|
||||
class PingHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return new JsonResponse(['ack' => time()]);
|
||||
}
|
||||
}
|
||||
56
test/AppTest/Handler/HomePageHandlerFactoryTest.php
Normal file
56
test/AppTest/Handler/HomePageHandlerFactoryTest.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AppTest\Handler;
|
||||
|
||||
use App\Handler\HomePageHandler;
|
||||
use App\Handler\HomePageHandlerFactory;
|
||||
use Mezzio\Router\RouterInterface;
|
||||
use Mezzio\Template\TemplateRendererInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class HomePageHandlerFactoryTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
/** @var ContainerInterface|ObjectProphecy */
|
||||
protected $container;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->container = $this->prophesize(ContainerInterface::class);
|
||||
$router = $this->prophesize(RouterInterface::class);
|
||||
|
||||
$this->container->get(RouterInterface::class)->willReturn($router);
|
||||
}
|
||||
|
||||
public function testFactoryWithoutTemplate()
|
||||
{
|
||||
$factory = new HomePageHandlerFactory();
|
||||
$this->container->has(TemplateRendererInterface::class)->willReturn(false);
|
||||
|
||||
$this->assertInstanceOf(HomePageHandlerFactory::class, $factory);
|
||||
|
||||
$homePage = $factory($this->container->reveal());
|
||||
|
||||
$this->assertInstanceOf(HomePageHandler::class, $homePage);
|
||||
}
|
||||
|
||||
public function testFactoryWithTemplate()
|
||||
{
|
||||
$this->container->has(TemplateRendererInterface::class)->willReturn(true);
|
||||
$this->container
|
||||
->get(TemplateRendererInterface::class)
|
||||
->willReturn($this->prophesize(TemplateRendererInterface::class));
|
||||
|
||||
$factory = new HomePageHandlerFactory();
|
||||
|
||||
$homePage = $factory($this->container->reveal());
|
||||
|
||||
$this->assertInstanceOf(HomePageHandler::class, $homePage);
|
||||
}
|
||||
}
|
||||
70
test/AppTest/Handler/HomePageHandlerTest.php
Normal file
70
test/AppTest/Handler/HomePageHandlerTest.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AppTest\Handler;
|
||||
|
||||
use App\Handler\HomePageHandler;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Mezzio\Router\RouterInterface;
|
||||
use Mezzio\Template\TemplateRendererInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
use function get_class;
|
||||
|
||||
class HomePageHandlerTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
/** @var ContainerInterface|ObjectProphecy */
|
||||
protected $container;
|
||||
|
||||
/** @var RouterInterface|ObjectProphecy */
|
||||
protected $router;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->container = $this->prophesize(ContainerInterface::class);
|
||||
$this->router = $this->prophesize(RouterInterface::class);
|
||||
}
|
||||
|
||||
public function testReturnsJsonResponseWhenNoTemplateRendererProvided()
|
||||
{
|
||||
$homePage = new HomePageHandler(
|
||||
get_class($this->container->reveal()),
|
||||
$this->router->reveal(),
|
||||
null
|
||||
);
|
||||
$response = $homePage->handle(
|
||||
$this->prophesize(ServerRequestInterface::class)->reveal()
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(JsonResponse::class, $response);
|
||||
}
|
||||
|
||||
public function testReturnsHtmlResponseWhenTemplateRendererProvided()
|
||||
{
|
||||
$renderer = $this->prophesize(TemplateRendererInterface::class);
|
||||
$renderer
|
||||
->render('app::home-page', Argument::type('array'))
|
||||
->willReturn('');
|
||||
|
||||
$homePage = new HomePageHandler(
|
||||
get_class($this->container->reveal()),
|
||||
$this->router->reveal(),
|
||||
$renderer->reveal()
|
||||
);
|
||||
|
||||
$response = $homePage->handle(
|
||||
$this->prophesize(ServerRequestInterface::class)->reveal()
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(HtmlResponse::class, $response);
|
||||
}
|
||||
}
|
||||
31
test/AppTest/Handler/PingHandlerTest.php
Normal file
31
test/AppTest/Handler/PingHandlerTest.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AppTest\Handler;
|
||||
|
||||
use App\Handler\PingHandler;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
use function json_decode;
|
||||
|
||||
class PingHandlerTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function testResponse()
|
||||
{
|
||||
$pingHandler = new PingHandler();
|
||||
$response = $pingHandler->handle(
|
||||
$this->prophesize(ServerRequestInterface::class)->reveal()
|
||||
);
|
||||
|
||||
$json = json_decode((string) $response->getBody());
|
||||
|
||||
$this->assertInstanceOf(JsonResponse::class, $response);
|
||||
$this->assertTrue(isset($json->ack));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user