Skip to content

Commit

Permalink
Upd: moved to PHP 8
Browse files Browse the repository at this point in the history
  • Loading branch information
debuss committed Jul 9, 2022
1 parent 98f4fac commit 05dc214
Show file tree
Hide file tree
Showing 34 changed files with 707 additions and 489 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@

## About Borsch Skeleton

Borsch is a simple and efficient [PSR-15](https://www.php-fig.org/psr/psr-15/) micro framework made to kick start your
app development by allowing you to develop using the tools you prefer, and provides minimal structure and facilities
to ease your development.
Sometimes, you don't need an overkill solution like [Laravel](https://laravel.com/) or [Symfony](https://symfony.com/).

`Borsch is a simple and efficient [PSR-15](https://www.php-fig.org/psr/psr-15/) micro framework made to kick start your
web app or API development by using the tools you prefer, and provides minimal structure and facilities to ease your
development.
`
It natively features :

* [Dependency Injection Container](https://github.com/borschphp/borsch-container)
Expand All @@ -30,7 +32,7 @@ Can be enriched with :
* [Templating](https://github.com/borschphp/borsch-smarty)
* Anything else you want

The framework is built around the DI Container, therefore everything is made around interfaces.
The framework is built around a [PSR-11](https://www.php-fig.org/psr/psr-11/) Container, therefore everything is made around interfaces.
If something is not at your taste, you can implement your own logic without having to modify everything.

## Get started
Expand Down
4 changes: 4 additions & 0 deletions bootstrap/defines.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php

define('__START_TIME__', microtime(true));
define('__ROOT_DIR__', realpath(dirname(__DIR__)));
8 changes: 4 additions & 4 deletions bootstrap/env.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<?php

require_once __DIR__.'/../vendor/autoload.php';
require_once app_path('vendor/autoload.php');

$environment_file = __DIR__.'/../config/environment.php';
$environment_file = config_path('environment.php');

// If environment file exists, load it so that it wont be necessary to parse and load .env file at every call.
// If environment file exists, load it so that it won't be necessary to parse and load .env file at every call.
if (file_exists($environment_file)) {
$environment = require_once $environment_file;
$_ENV = array_merge($_ENV, $environment);
return;
}

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__.'/..');
$dotenv = Dotenv\Dotenv::createImmutable(app_path());
$environment = $dotenv->load();

// In production, save the environment in a file so that it wont be necessary to parse and load .env file at every call.
Expand Down
72 changes: 61 additions & 11 deletions bootstrap/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @param mixed $default
* @return mixed
*/
function env(string $key, $default = null)
function env(string $key, mixed $default = null): mixed
{
$value = $_ENV[$key] ?? false;

Expand All @@ -16,17 +16,67 @@ function env(string $key, $default = null)
}

$cleaned_value = trim(strtolower($value), '() \n\r\t\v\x00');
switch ($cleaned_value) {
case 'true':
case 'false':
return filter_var($cleaned_value, FILTER_VALIDATE_BOOLEAN);
return match ($cleaned_value) {
'true', 'false' => filter_var($cleaned_value, FILTER_VALIDATE_BOOLEAN),
'empty' => '',
'null' => null,
default => trim($value, '"\''),
};
}

case 'empty':
return '';
/**
* Returns the path to the root app directory, appended with extra path.
*
* @param string ...$paths
* @return string
*/
function app_path(string ...$paths): string
{
$path = array_reduce($paths, fn($acc, $cur) => $acc.'/'.ltrim($cur, ' /\\'), '');

case 'null':
return null;
}
return __ROOT_DIR__.$path;
}

return trim($value, '"\'');
/**
* Returns the path to the config directory, appended with extra path.
*
* @param string $path
* @return string
*/
function config_path(string $path): string
{
return app_path('config', $path);
}

/**
* Returns the path to the storage directory, appended with extra path.
*
* @param string ...$paths
* @return string
*/
function storage_path(string ...$paths): string
{
return call_user_func_array('app_path', array_merge(['storage'], $paths));
}

/**
* Returns the path to the cache directory, appended with extra path.
*
* @param string $path
* @return string
*/
function cache_path(string $path = ''): string
{
return storage_path('cache', $path);
}

/**
* Returns the path to the logs' directory, appended with extra path.
*
* @param string $path
* @return string
*/
function logs_path(string $path = ''): string
{
return storage_path('logs', $path);
}
16 changes: 9 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,30 @@
"authors": [
{
"name": "Alexandre DEBUSSCHERE",
"email": "zizilex@gmail.com"
"email": "alexandre.debusschere@hey.com"
}
],
"require": {
"php": "^7.2|^8.0",
"php": "^8.0",
"ext-json": "*",
"ext-libxml": "*",
"ext-pdo": "*",
"ext-simplexml": "*",
"borschphp/application": "^0",
"borschphp/chef": "^0.1.0",
"laminas/laminas-diactoros": "^2.8",
"monolog/monolog": "^2.0",
"borschphp/application": "^1",
"borschphp/chef": "^1",
"laminas/laminas-diactoros": "^2",
"monolog/monolog": "^2",
"vlucas/phpdotenv": "v5.1.0"
},
"require-dev": {
"phpunit/phpunit": "^8"
"phpunit/phpunit": "^9"
},
"autoload": {
"psr-4": {
"App\\": "src/"
},
"files": [
"bootstrap/defines.inc.php",
"bootstrap/helpers.php",
"bootstrap/env.php"
]
Expand Down
101 changes: 57 additions & 44 deletions config/container.php
Original file line number Diff line number Diff line change
@@ -1,85 +1,98 @@
<?php

use App\Handler\UserHandler;
use App\Listener\MonologListener;
use App\Middleware\ErrorHandlerMiddleware;
use App\Repository\InMemoryUserRepository;
use App\Repository\UserRepositoryInterface;
use Borsch\Application\App;
use Borsch\Application\ApplicationInterface;
use Borsch\Container\Container;
use Borsch\RequestHandler\ApplicationRequestHandlerInterface;
use Borsch\RequestHandler\RequestHandler;
use Borsch\Router\FastRouteRouter;
use Borsch\Router\RouterInterface;
use App\{Handler\PeoplesHandler,
Listener\MonologListener,
Middleware\ErrorHandlerMiddleware,
Repository\PeopleRepositoryInterface,
Repository\SQLitePeopleRepository};
use Borsch\{Application\App,
Application\ApplicationInterface,
Container\Container,
RequestHandler\ApplicationRequestHandlerInterface,
RequestHandler\RequestHandler,
Router\FastRouteRouter,
Router\RouterInterface};
use Laminas\Diactoros\ServerRequestFactory;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\{Handler\StreamHandler, Logger};
use Psr\Http\Message\ServerRequestInterface;

$container = new Container();

/*
* Application definitions
* -----------------------
*
* Main Borsch App definitions.
* Here you can inject the basic dependency like the App instance, Router instance,
* PSR-* instances, etc.
* Main Borsch App definitions (like the App instance, Router instance, PSR-* instances, etc).
*/

$container->set(ApplicationInterface::class, App::class);
$container->set(RouterInterface::class, function() {
$container->set(RouterInterface::class, function () {
$router = new FastRouteRouter();
if (env('APP_ENV') == 'production') {
$router->setCacheFile(__DIR__.'/../../storage/cache/routes.cache.php');
$router->setCacheFile(cache_path('routes.cache.php'));
}

return $router;
})->cache(true);
$container->set(ApplicationRequestHandlerInterface::class, RequestHandler::class);
$container->set(ServerRequestInterface::class, function() {
return ServerRequestFactory::fromGlobals();
});
$container->set(ServerRequestInterface::class, fn() => ServerRequestFactory::fromGlobals());

/*
* Pipeline Middlewares definitions
* --------------------------------
*
* Here we configure ErrorHandlerMiddleware with a Monolog listener so that our exceptions will be logged.
*
* ImplicitHeadMiddleware and RouteMiddleware have a constructor that requires dependency.
* When you add a new MiddlewareInterface in the pipeline, and it requires dependencies in the constructor,
* then add the necessary definitions below.
* Log & Monitoring definitions
* ----------------------------
* A default Logger is defined, it can be used in our middlewares, handlers or any other stuff as well.
*/
$container->set(ErrorHandlerMiddleware::class, function() {

$container->set(Logger::class, function () {
$name = env('APP_NAME', 'Borsch') ?: 'Borsch';
$logger = new Logger($name);
$logger->pushHandler(new StreamHandler(sprintf(
'%s/../storage/logs/%s.log',
__DIR__,
$logger->pushHandler(new StreamHandler(logs_path(sprintf(
'%s.log',
env('LOG_CHANNEL', 'app')
)));
))));

$error_handler = new ErrorHandlerMiddleware();
$error_handler->addListener(new MonologListener($logger));
return $logger;
})-> cache(true);

return $error_handler;
});
/*
* Pipeline Middlewares definitions
* --------------------------------
* Here we configure ErrorHandlerMiddleware with a Monolog listener so that our exceptions will be logged.
*/

$container
->set(ErrorHandlerMiddleware::class)
->addMethod('addListener', [$container->get(MonologListener::class)]);

/*
* Routes Handlers definitions
* ---------------------------
*
* As for pipeline middlewares, your routes handlers that have dependency must be listed here.
* Our HomeHandler handler uses an instance of TemplateRendererInterface to display an HTML page, so it is listed below.
*/
$container->set(UserHandler::class);

$container->set(PeoplesHandler::class);

/*
* Database
* --------
* This skeleton implements a simple CRUD API that stores and updates a SQLite database via PDO.
*/

$container->set(PDO::class, function () {
$pdo = new PDO('sqlite:'.storage_path('database.sqlite'));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

return $pdo;
})->cache(true);

/*
* Match the UserRepositoryInterface with InMemoryUserRepository so that it can be used in UserHandler upper.
*/

$container
->set(UserRepositoryInterface::class, InMemoryUserRepository::class)
->set(PeopleRepositoryInterface::class, SQLitePeopleRepository::class)
->cache(true);


return $container;
44 changes: 23 additions & 21 deletions config/pipeline.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<?php

use App\Middleware\ApiMiddleware;
use App\Middleware\BodyParserMiddleware;
use App\Middleware\ContentLengthMiddleware;
use App\Middleware\DispatchMiddleware;
use App\Middleware\ErrorHandlerMiddleware;
use App\Middleware\ImplicitHeadMiddleware;
use App\Middleware\ImplicitOptionsMiddleware;
use App\Middleware\MethodNotAllowedMiddleware;
use App\Middleware\NotFoundHandlerMiddleware;
use App\Middleware\RouteMiddleware;
use App\Middleware\TrailingSlashMiddleware;
use App\Middleware\UploadedFilesParserMiddleware;
use App\Middleware\{
ApiKeyValidatorMiddleware,
BodyParserMiddleware,
ContentLengthMiddleware,
DispatchMiddleware,
ErrorHandlerMiddleware,
ImplicitHeadMiddleware,
ImplicitOptionsMiddleware,
MethodNotAllowedMiddleware,
NotFoundHandlerMiddleware,
RouteMiddleware,
TrailingSlashMiddleware,
UploadedFilesParserMiddleware
};
use Borsch\Application\App;

/**
Expand All @@ -28,14 +30,6 @@
$app->pipe(TrailingSlashMiddleware::class);
$app->pipe(ContentLengthMiddleware::class);

// Middleware can be attached to specific paths, allowing you to mix and match
// applications under a common domain.
$app->pipe('/api', [
ApiMiddleware::class,
BodyParserMiddleware::class,
UploadedFilesParserMiddleware::class
]);

// Register the routing middleware in the pipeline.
// It will add the Borsch\Router\RouteResult request attribute.
$app->pipe(RouteMiddleware::class);
Expand All @@ -49,10 +43,18 @@
$app->pipe(ImplicitOptionsMiddleware::class);
$app->pipe(MethodNotAllowedMiddleware::class);

// Middleware can be attached to specific paths, allowing you to mix and match
// applications under a common domain.
$app->pipe('/api', ApiKeyValidatorMiddleware::class);
$app->pipe('/api/peoples', [
BodyParserMiddleware::class,
UploadedFilesParserMiddleware::class
]);

// This will take care of generating the response of your matched route.
$app->pipe(DispatchMiddleware::class);

// If no Response is returned by any middleware, then send a 404 Not Found response.
// You can provide other fallback middleware to execute.
// You can provide other fallback middleware to execute.
$app->pipe(NotFoundHandlerMiddleware::class);
};
Loading

0 comments on commit 05dc214

Please sign in to comment.