Skip to content
Snippets Groups Projects
Commit 581ff908 authored by Elise Moreau's avatar Elise Moreau
Browse files

init slim framework files

parent b992cf60
Branches
No related tags found
No related merge requests found
Showing with 3353 additions and 1 deletion
json_path: coveralls-upload.json
language: php
dist: trusty
matrix:
include:
- php: 7.2
- php: 7.3
- php: 7.4
env: ANALYSIS='true'
- php: nightly
allow_failures:
- php: nightly
before_script:
- composer require php-coveralls/php-coveralls:^2.2.0
- composer install -n
script:
- if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/phpunit --coverage-clover clover.xml ; fi
- if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/phpstan analyse src ; fi
after_success:
- if [[ "$ANALYSIS" == 'true' ]]; then vendor/bin/php-coveralls --coverage_clover=clover.xml -v ; fi
# How to Contribute
## Pull Requests
1. Fork the Slim Skeleton repository
2. Create a new branch for each feature or improvement
3. Send a pull request from each feature branch to the **4.x** branch
It is very important to separate new features or improvements into separate feature branches, and to send a
pull request for each branch. This allows us to review and pull in new features or improvements individually.
## Style Guide
All pull requests must adhere to the [PSR-2 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md).
# project-covid
# Slim Framework 4 Skeleton Application
[![Coverage Status](https://coveralls.io/repos/github/slimphp/Slim-Skeleton/badge.svg?branch=master)](https://coveralls.io/github/slimphp/Slim-Skeleton?branch=master)
Use this skeleton application to quickly setup and start working on a new Slim Framework 4 application. This application uses the latest Slim 4 with Slim PSR-7 implementation and PHP-DI container implementation. It also uses the Monolog logger.
This skeleton application was built for Composer. This makes setting up a new Slim Framework application quick and easy.
## Install the Application
Run this command from the directory in which you want to install your new Slim Framework application.
```bash
composer create-project slim/slim-skeleton [my-app-name]
```
Replace `[my-app-name]` with the desired directory name for your new application. You'll want to:
* Point your virtual host document root to your new application's `public/` directory.
* Ensure `logs/` is web writable.
To run the application in development, you can run these commands
```bash
cd [my-app-name]
composer start
```
Or you can use `docker-compose` to run the app with `docker`, so you can run these commands:
```bash
cd [my-app-name]
docker-compose up -d
```
After that, open `http://localhost:8080` in your browser.
Run this command in the application directory to run the test suite
```bash
composer test
```
That's it! Now go build something cool.
<?php
declare(strict_types=1);
use DI\ContainerBuilder;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\Processor\UidProcessor;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
return function (ContainerBuilder $containerBuilder) {
$containerBuilder->addDefinitions([
LoggerInterface::class => function (ContainerInterface $c) {
$settings = $c->get('settings');
$loggerSettings = $settings['logger'];
$logger = new Logger($loggerSettings['name']);
$processor = new UidProcessor();
$logger->pushProcessor($processor);
$handler = new StreamHandler($loggerSettings['path'], $loggerSettings['level']);
$logger->pushHandler($handler);
return $logger;
},
]);
};
<?php
declare(strict_types=1);
use App\Application\Middleware\SessionMiddleware;
use Slim\App;
return function (App $app) {
$app->add(SessionMiddleware::class);
};
<?php
declare(strict_types=1);
use App\Domain\User\UserRepository;
use App\Infrastructure\Persistence\User\InMemoryUserRepository;
use DI\ContainerBuilder;
return function (ContainerBuilder $containerBuilder) {
// Here we map our UserRepository interface to its in memory implementation
$containerBuilder->addDefinitions([
UserRepository::class => \DI\autowire(InMemoryUserRepository::class),
]);
};
<?php
declare(strict_types=1);
use App\Application\Actions\User\ListUsersAction;
use App\Application\Actions\User\ViewUserAction;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
use Slim\Interfaces\RouteCollectorProxyInterface as Group;
return function (App $app) {
$app->options('/{routes:.*}', function (Request $request, Response $response) {
// CORS Pre-Flight OPTIONS Request Handler
return $response;
});
$app->get('/', function (Request $request, Response $response) {
$response->getBody()->write('Hello world!');
return $response;
});
$app->group('/users', function (Group $group) {
$group->get('', ListUsersAction::class);
$group->get('/{id}', ViewUserAction::class);
});
};
<?php
declare(strict_types=1);
use DI\ContainerBuilder;
use Monolog\Logger;
return function (ContainerBuilder $containerBuilder) {
// Global Settings Object
$containerBuilder->addDefinitions([
'settings' => [
'displayErrorDetails' => true, // Should be set to false in production
'logger' => [
'name' => 'slim-app',
'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log',
'level' => Logger::DEBUG,
],
],
]);
};
{
"name": "slim/slim-skeleton",
"description": "A Slim Framework skeleton application for rapid development",
"keywords": [
"microframework",
"rest",
"router",
"psr7"
],
"homepage": "http://github.com/slimphp/Slim-Skeleton",
"license": "MIT",
"authors": [
{
"name": "Josh Lockhart",
"email": "info@joshlockhart.com",
"homepage": "http://www.joshlockhart.com/"
},
{
"name": "Pierre Berube",
"email": "pierre@lgse.com",
"homepage": "http://www.lgse.com/"
}
],
"require": {
"php": "^7.2",
"ext-json": "*",
"monolog/monolog": "^2.1",
"php-di/php-di": "^6.2",
"slim/psr7": "^1.1",
"slim/slim": "^4.5"
},
"require-dev": {
"jangregor/phpstan-prophecy": "^0.8.0",
"phpstan/extension-installer": "^1.0.4",
"phpstan/phpstan": "^0.12.37",
"phpunit/phpunit": "^8.5"
},
"config": {
"process-timeout": 0,
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"start": "php -S localhost:8080 -t public",
"test": "phpunit"
}
}
This diff is collapsed.
version: '3.7'
volumes:
logs:
driver: local
services:
slim:
image: php:7-alpine
working_dir: /var/www
command: php -S 0.0.0.0:8080 -t public
environment:
docker: "true"
ports:
- 8080:8080
volumes:
- .:/var/www
- logs:/var/www/logs
Your Slim Framework application's log files will be written to this directory.
parameters:
level: 4
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/7.1/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutChangesToGlobalState="true"
beStrictAboutOutputDuringTests="true"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>
</phpunit>
<IfModule mod_rewrite.c>
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the
# absolute physical path to the directory that contains this htaccess file.
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
<?php
declare(strict_types=1);
use App\Application\Handlers\HttpErrorHandler;
use App\Application\Handlers\ShutdownHandler;
use App\Application\ResponseEmitter\ResponseEmitter;
use DI\ContainerBuilder;
use Slim\Factory\AppFactory;
use Slim\Factory\ServerRequestCreatorFactory;
require __DIR__ . '/../vendor/autoload.php';
// Instantiate PHP-DI ContainerBuilder
$containerBuilder = new ContainerBuilder();
if (false) { // Should be set to true in production
$containerBuilder->enableCompilation(__DIR__ . '/../var/cache');
}
// Set up settings
$settings = require __DIR__ . '/../app/settings.php';
$settings($containerBuilder);
// Set up dependencies
$dependencies = require __DIR__ . '/../app/dependencies.php';
$dependencies($containerBuilder);
// Set up repositories
$repositories = require __DIR__ . '/../app/repositories.php';
$repositories($containerBuilder);
// Build PHP-DI Container instance
$container = $containerBuilder->build();
// Instantiate the app
AppFactory::setContainer($container);
$app = AppFactory::create();
$callableResolver = $app->getCallableResolver();
// Register middleware
$middleware = require __DIR__ . '/../app/middleware.php';
$middleware($app);
// Register routes
$routes = require __DIR__ . '/../app/routes.php';
$routes($app);
/** @var bool $displayErrorDetails */
$displayErrorDetails = $container->get('settings')['displayErrorDetails'];
// Create Request object from globals
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
// Create Error Handler
$responseFactory = $app->getResponseFactory();
$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory);
// Create Shutdown Handler
$shutdownHandler = new ShutdownHandler($request, $errorHandler, $displayErrorDetails);
register_shutdown_function($shutdownHandler);
// Add Routing Middleware
$app->addRoutingMiddleware();
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, false, false);
$errorMiddleware->setDefaultErrorHandler($errorHandler);
// Run App & Emit Response
$response = $app->handle($request);
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
<?php
declare(strict_types=1);
namespace App\Application\Actions;
use App\Domain\DomainException\DomainRecordNotFoundException;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Log\LoggerInterface;
use Slim\Exception\HttpBadRequestException;
use Slim\Exception\HttpNotFoundException;
abstract class Action
{
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var Request
*/
protected $request;
/**
* @var Response
*/
protected $response;
/**
* @var array
*/
protected $args;
/**
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* @param Request $request
* @param Response $response
* @param array $args
* @return Response
* @throws HttpNotFoundException
* @throws HttpBadRequestException
*/
public function __invoke(Request $request, Response $response, $args): Response
{
$this->request = $request;
$this->response = $response;
$this->args = $args;
try {
return $this->action();
} catch (DomainRecordNotFoundException $e) {
throw new HttpNotFoundException($this->request, $e->getMessage());
}
}
/**
* @return Response
* @throws DomainRecordNotFoundException
* @throws HttpBadRequestException
*/
abstract protected function action(): Response;
/**
* @return array|object
* @throws HttpBadRequestException
*/
protected function getFormData()
{
$input = json_decode(file_get_contents('php://input'));
if (json_last_error() !== JSON_ERROR_NONE) {
throw new HttpBadRequestException($this->request, 'Malformed JSON input.');
}
return $input;
}
/**
* @param string $name
* @return mixed
* @throws HttpBadRequestException
*/
protected function resolveArg(string $name)
{
if (!isset($this->args[$name])) {
throw new HttpBadRequestException($this->request, "Could not resolve argument `{$name}`.");
}
return $this->args[$name];
}
/**
* @param array|object|null $data
* @return Response
*/
protected function respondWithData($data = null, int $statusCode = 200): Response
{
$payload = new ActionPayload($statusCode, $data);
return $this->respond($payload);
}
/**
* @param ActionPayload $payload
* @return Response
*/
protected function respond(ActionPayload $payload): Response
{
$json = json_encode($payload, JSON_PRETTY_PRINT);
$this->response->getBody()->write($json);
return $this->response
->withHeader('Content-Type', 'application/json')
->withStatus($payload->getStatusCode());
}
}
<?php
declare(strict_types=1);
namespace App\Application\Actions;
use JsonSerializable;
class ActionError implements JsonSerializable
{
public const BAD_REQUEST = 'BAD_REQUEST';
public const INSUFFICIENT_PRIVILEGES = 'INSUFFICIENT_PRIVILEGES';
public const NOT_ALLOWED = 'NOT_ALLOWED';
public const NOT_IMPLEMENTED = 'NOT_IMPLEMENTED';
public const RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND';
public const SERVER_ERROR = 'SERVER_ERROR';
public const UNAUTHENTICATED = 'UNAUTHENTICATED';
public const VALIDATION_ERROR = 'VALIDATION_ERROR';
public const VERIFICATION_ERROR = 'VERIFICATION_ERROR';
/**
* @var string
*/
private $type;
/**
* @var string
*/
private $description;
/**
* @param string $type
* @param string|null $description
*/
public function __construct(string $type, ?string $description)
{
$this->type = $type;
$this->description = $description;
}
/**
* @return string
*/
public function getType(): string
{
return $this->type;
}
/**
* @param string $type
* @return self
*/
public function setType(string $type): self
{
$this->type = $type;
return $this;
}
/**
* @return string
*/
public function getDescription(): string
{
return $this->description;
}
/**
* @param string|null $description
* @return self
*/
public function setDescription(?string $description = null): self
{
$this->description = $description;
return $this;
}
/**
* @return array
*/
public function jsonSerialize()
{
$payload = [
'type' => $this->type,
'description' => $this->description,
];
return $payload;
}
}
<?php
declare(strict_types=1);
namespace App\Application\Actions;
use JsonSerializable;
class ActionPayload implements JsonSerializable
{
/**
* @var int
*/
private $statusCode;
/**
* @var array|object|null
*/
private $data;
/**
* @var ActionError|null
*/
private $error;
/**
* @param int $statusCode
* @param array|object|null $data
* @param ActionError|null $error
*/
public function __construct(
int $statusCode = 200,
$data = null,
?ActionError $error = null
) {
$this->statusCode = $statusCode;
$this->data = $data;
$this->error = $error;
}
/**
* @return int
*/
public function getStatusCode(): int
{
return $this->statusCode;
}
/**
* @return array|null|object
*/
public function getData()
{
return $this->data;
}
/**
* @return ActionError|null
*/
public function getError(): ?ActionError
{
return $this->error;
}
/**
* @return array
*/
public function jsonSerialize()
{
$payload = [
'statusCode' => $this->statusCode,
];
if ($this->data !== null) {
$payload['data'] = $this->data;
} elseif ($this->error !== null) {
$payload['error'] = $this->error;
}
return $payload;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment