Skip to content
This repository has been archived by the owner on Sep 27, 2022. It is now read-only.

#17 upgrade to slim 4 #18

Open
wants to merge 28 commits into
base: slim-4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c998c0f
update composer require definitions
gustavofabiane Feb 4, 2020
0e2c6c7
update ErrorHandler signature for Slim 4
gustavofabiane Feb 4, 2020
9212b43
update settings
gustavofabiane Feb 4, 2020
845edcb
update dependencies definitions
gustavofabiane Feb 4, 2020
eef6061
bootstrap application in separated file
gustavofabiane Feb 4, 2020
cdfbc3e
update app middleware
gustavofabiane Feb 4, 2020
784990c
update auth service
gustavofabiane Feb 4, 2020
a21d4c0
remove template
gustavofabiane Feb 4, 2020
a0d4214
update dependencies
gustavofabiane Feb 4, 2020
23c7fc7
update phinx settings
gustavofabiane Feb 4, 2020
1297aea
update definitions and middleware
gustavofabiane Feb 4, 2020
5167ac7
update route definitions
gustavofabiane Feb 4, 2020
a97735b
update base test case to use app as RequestHandlerInterface
gustavofabiane Feb 4, 2020
4089406
update authorization header
gustavofabiane Feb 4, 2020
c47f902
inject default dependencies used by all controllers in base controller
gustavofabiane Feb 5, 2020
aaea589
update dependencies, routes and settings
gustavofabiane Feb 6, 2020
b7bbac8
fix middleware order
gustavofabiane Feb 6, 2020
e80309f
update HomepageTest
gustavofabiane Feb 6, 2020
50aeb13
update services
gustavofabiane Feb 6, 2020
d4c23e0
update controllers
gustavofabiane Feb 6, 2020
b5a0b49
remove unnecessary response parameter from ArticleController:store ac…
gustavofabiane Feb 6, 2020
5561ab1
fix issue in article list
gustavofabiane Feb 6, 2020
5425042
add required platform extensions in composer.json
gustavofabiane Feb 6, 2020
5b96937
fix test case function name
gustavofabiane Feb 6, 2020
1803291
fix ternary in timestamps fields which were using an undefined variab…
gustavofabiane Feb 6, 2020
c3b7047
update directory structure
gustavofabiane Feb 13, 2020
5323cde
update readme with changes for new version
gustavofabiane Feb 18, 2020
e2316a7
Merge branch 'slim-4' into feature/upgrade-to-slim-4
gustavofabiane Jul 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,25 @@
}
],
"require": {
"php": ">=7.0",
"slim/slim": "^3.9",
"slim/php-view": "^2.0",
"php": ">=7.2",
"ext-json": "*",
"ext-pdo": "*",
"ext-pdo_mysql": "*",
"slim/slim": "^4.0",
"monolog/monolog": "^1.23",
"illuminate/database": "^5.5",
"robmorgan/phinx": "dev-master#4c26aeb",
"robmorgan/phinx": "^0.11.4",
"vlucas/phpdotenv": "^2.4",
"tuupola/slim-jwt-auth": "^2.3",
"tuupola/slim-jwt-auth": "^3.4",
"fzaninotto/faker": "^1.7",
"respect/validation": "^1.1",
"league/fractal": "^0.17.0"
"league/fractal": "^0.17.0",
"nyholm/psr7": "^1.2",
"nyholm/psr7-server": "^0.4.1",
"php-di/php-di": "^6.0"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"phpunit/phpunit": "^6.4"
},
"autoload": {
Expand Down
21 changes: 10 additions & 11 deletions docs/directory.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,23 @@ src/Conduit
│   │   ├── LoginController.php
│   │   └── RegisterController.php
│   ├── BaseController.php
│   └── User # User/Profile related endpoints
│   ├── ProfileController.php
│   └── UserController.php
│   ├── User # User/Profile related endpoints
│   | ├── ProfileController.php
│   | └── UserController.php
| └── BaseController.php # Other controllers extends basic behavior from BaseController
├── Exceptions # Mainly to handle ModelNotFoundException and return 404 response.
│   └── ErrorHandler.php
├── Middleware # Custom middlewares should be defined here.
│   └── Cors.php # Middleware that handle CORS options
│   └── OptionalAuth.php # Middleware for optional routes when the reqest has token.
│   └── RemoveTrailingSlash.php # Remove trailing slash from URI path.
├── Models
│   ├── Article.php
│   ├── Comment.php
│   ├── Tag.php
│   └── User.php
├── Services
│   ├── Auth
│   │   ├── Auth.php # Generate JWT Token and retrieve request user
│   │   └── AuthServiceProvider.php
│   └── Database
│   └── EloquentServiceProvider.php
├── Services/Auth
│   └── Auth.php # Generate JWT Token and retrieve request user
├── Transformers # Transform Models into JSON for response
│   ├── ArticleTransformer.php
│   ├── AuthorTransformer.php
Expand Down Expand Up @@ -69,12 +68,12 @@ src/Conduit
│   └── index.php
├── src # The App Code
│   ├── Conduit
│   ├── app.php
│   ├── boot.php
│   ├── dependencies.php
│   ├── middleware.php
│   ├── routes.php
│   └── settings.php
├── templates
│   └── index.phtml
├── tests
│   ├── Functional
│   ├── Unit
Expand Down
9 changes: 5 additions & 4 deletions phinx.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<?php

require_once './vendor/autoload.php';
$settings = require './src/settings.php';
$app = new \Slim\App($settings);

/** @var Slim\App $app */
$app = require './src/app.php';

$container = $app->getContainer();
$container->register(new \Conduit\Services\Database\EloquentServiceProvider());
$config = $container['settings']['database'];
$config = $container->get('settings')['database'];

return [
'paths' => [
Expand Down
3 changes: 3 additions & 0 deletions public/.htaccess
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
# absolute physical path to the directory that contains this htaccess file.
# RewriteBase /

# Provide Authorization header
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
16 changes: 2 additions & 14 deletions public/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,8 @@

require __DIR__ . '/../vendor/autoload.php';

session_start();

// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$app = new \Slim\App($settings);

// Set up dependencies
require __DIR__ . '/../src/dependencies.php';

// Register middleware
require __DIR__ . '/../src/middleware.php';

// Register routes
require __DIR__ . '/../src/routes.php';
// Bootstrap application
$app = require __DIR__ . '/../src/app.php';

// Run app
$app->run();
105 changes: 67 additions & 38 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ The app is built using **[Slim](https://www.slimframework.com/)**. However, ther
composer install
```
**List of Dependencies**
- [php-di/php-di](http://php-di.org/) PSR-11 Container implemenation dependency management
- [nyholm/psr7](https://github.com/Nyholm/psr7) PSR-7 and PSR-17 implementations
- [nyholm/psr7-server](https://github.com/Nyholm/psr7-server) PSR-7 server creation helpers
- [tuupola/slim-jwt-auth](https://appelsiini.net/projects/slim-jwt-auth/) To manage the api authentication using JWT.
- [respect/validation](http://respect.github.io/Validation/) Validate the request parameters.
- [league/fractal](https://fractal.thephpleague.com/) Transfer data models to JSON for the Api responses.
Expand All @@ -103,7 +106,8 @@ The `.env` is loaded using `vlucas/phpdotenv` through these [lines of code](http
## Directory Structure
> Open the project directory using your favorite editor.

The app follows the structure of [Slim skeleton application](https://github.com/slimphp/Slim-Skeleton) with minor changes.
The app follows the structure of [Slim 3 skeleton application](https://github.com/slimphp/Slim-Skeleton/tree/3.1.8) with minor changes.
After upgrade from Slim 4 the structure were adapted to work with the new version of the framework, that is based on the [new skeleton for Slim 4](https://github.com/slimphp/Slim-Skeleton).
The skeleton is a good starting point when developing with Slim framework.
A detailed overview of the directory structure can be found at [this page](docs/directory.md).

Expand Down Expand Up @@ -180,14 +184,14 @@ You can check the api by visiting [http://localhost:8080/api/articles](http://lo
> There is Postman [collection made by Thinkster](https://github.com/gothinkster/realworld/blob/master/api/Conduit.postman_collection.json) team you could use.
### Entry Point:
The server will direct all requests to [index.php](public/index.php).
There, we boot the app by creating an instance of Slim\App and require all the settings and relevant files.

Finally, we run the app by calling `$app->run()`, which will process the request and send the response.
There, we get the application instance from `app.php` where all dependencies, routes and middleware are defined.
> We include four important files into the index.php: `settings.php`, `dependencies.php`, `middleware.php`, `routes.php`
> I's a good idea to check them before continuing.

Finally, we run the app by calling `$app->run()`, which will process the request and send the response.

### The App Instance
The instance of Slim\App (`$app`) holds the app settings, routes, and dependencies.
The instance of Slim\App (`$app`) which extends from Slim\Interfaces\RouteCollectorProxyInterface and holds the app settings, routes, and dependencies.

We register routes and methods by calling methods on the `$app` instance.

Expand All @@ -200,56 +204,85 @@ Later, when we need a service or a class we ask the container, and it will insta

The container is configured in the [dependencies.php](src/dependencies.php).
We start be retrieving the container from the `$app` instance and configure the required services:
Dependencies are registered by the `$containerBuilder` instance with array of definitions where array keys are the dependenci identifier and
its value the dependency resolver. We recommend to check [PHP-DI docs](http://php-di.org/doc/definition.html) for more information on Container definitions.
```php
$container = $app->getContainer();

$container['logger'] = function ($c) {
$settings = $c->get('settings')['logger'];
$logger = new Monolog\Logger($settings['name']);
$logger->pushProcessor(new Monolog\Processor\UidProcessor());
$logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], $settings['level']));

return $logger;
use function DI\get;

/**
* Application dependencies definitions
*/
return function (ContainerBuilder $containerBuilder): void {

$containerBuilder->addDefinitions([
LoggerInterface::class => get('logger'),
'logger' => function ($c) {
$settings = $c->get('settings')['logger'];
$logger = new Logger($settings['name']);
$logger->pushProcessor(new UidProcessor());
$logger->pushHandler(new StreamHandler($settings['path'], $settings['level']));

return $logger;
},
]);
};
```
The above code registers a configured instance of the `logger` in the container. Later we can ask for the `logger`
```php
$container = $containerBuilder->build();

$logger = $container->get('logger');
$logger->info('log message');
```

We register two middleware with the container:
> We will see them in action later in the [Authentication](#authentication-jwt) section.
> We will see about `jwt` and `optionalAuth` in action later in the [Authentication](#authentication-jwt) section.

> `RemoveTrailingSlash` and `Cors` are application level middleware.
```php
// Jwt Middleware
$container['jwt'] = function ($c) {

$jws_settings = $c->get('settings')['jwt'];

return new \Slim\Middleware\JwtAuthentication($jws_settings);
};

// Optional Auth Middleware
$container['optionalAuth'] = function ($c) {
return new OptionalAuth($c);
};
// Middleware definitions
$containerBuilder->addDefinitions([

// JWT Middleware
'jwt' => function ($c) {
return new JwtAuthentication($c->get('settings')['jwt']);
},

// Optional Auth Middleware
'optionalAuth' => function ($c) {
return new OptionalAuth($c->get('jwt'));
},

// Remove trailing slash from URI path
RemoveTrailingSlash::class => function () {
$responseFactory = NyholmPsr17Factory::getResponseFactory();
return new RemoveTrailingSlash($responseFactory);
},

// CORS middleware
Cors::class => function ($c) {
return new Cors($c->get('settings')['cors']);
},
]);
```

#### Service Providers
#### Boot Services
The above services example will not be instantiated until we call for them.
However, we could use a service provider to have some services available without retrieving them from the container.

Our app use Eloquent ORM to handle our data models. Eloquent must be configured and booted.
We do this in the [EloquentServiceProvider](src/Conduit/Services/Database/EloquentServiceProvider.php) class,
and register the service provider with the container.
We do this in the [boot.php](src/boot.php) file by retrieving the database manager from the container and
initializing Eloquent.
```php
$container->register(new \Conduit\Services\Database\EloquentServiceProvider());
$db = $container->get('db');
$db->setAsGlobal();
$db->bootEloquent();
```
For more details check [Dependency Container](https://www.slimframework.com/docs/concepts/di.html) documentations.
For more details check [Dependency Container](https://www.slimframework.com/docs/v4/concepts/di.html) documentations.


## Request-Response Cycle
All requests go through the same cycle: `routing > middleware > conroller > response`
All requests go through the same cycle: `routing > middleware > controller > response`
### Routes:
> Check the list of endpoints defined by the [RealWorld API Spec](https://github.com/gothinkster/realworld/tree/master/api#endpoints)

Expand Down Expand Up @@ -282,10 +315,6 @@ for example.

### Controllers
After passing through all assigned middleware, the request will be processed by a controller.
> Note: You could process the request inside a closure passed as the second argument to the method defining the route.
> For example, [the last route](https://github.com/gothinkster/slim-php-realworld-example-app/blob/c826cb831e2de6292f1feb5a1ba3584221f40795/src/routes.php#L88-L95),
which is left as an example from the skeleton project, handles the request in a closure
> [Check the documentations](https://www.slimframework.com/docs/objects/router.html#route-callbacks).

The controller's job is to validate the request data, check for authorization, process the request by calling a model or do other jobs,
and eventually return a response in the form of JSON response.
Expand Down Expand Up @@ -364,7 +393,7 @@ The authorization is handled by the controller. Simply, the controller will comp
If not authorized, the controller will return a 403 response.
```php
if ($requestUser->id != $article->user_id) {
return $response->withJson(['message' => 'Forbidden'], 403);
return $this->jsonResponse(['message' => 'Forbidden'], 403);
}
```
However, in a bigger application you might want to implement more robust authorization system.
Expand Down
Loading