Top Banner
@asgrim Kicking off with Zend Expressive and Doctrine ORM James Titcumb php[MiNDS] March 2018 Follow along (optional): https://github.com/asgrim/book-library
105

Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

Mar 18, 2018

Download

Technology

James Titcumb
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Kicking off with Zend Expressiveand Doctrine ORM

James Titcumbphp[MiNDS] March 2018

Follow along (optional): https://github.com/asgrim/book-library

Page 2: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

$ whoami

James Titcumb

www.jamestitcumb.com

www.roave.com

@asgrim

Page 3: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

What is Zend Expressive?

Page 4: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Layers of an Expressive application

Expressive

Stratigility

Diactoros

PSR-7 Interface

DIRouter Template

Your Application

Page 5: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Layers of an Expressive application

Expressive

Stratigility

Diactoros

PSR-7 Interface

DIRouter Template

Your Application

Page 6: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

PSR-7HTTP Message Interfaces

Page 7: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

HTTP Request

POST /talk HTTP/1.1

Host: phpminds.org

foo=bar&baz=bat

Page 8: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

HTTP Response

HTTP/1.1 200 OK

Content-Type: text/plain

This is the response body

Page 9: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Layers of an Expressive application

Expressive

Stratigility

Diactoros

PSR-7 Interface

DIRouter Template

Your Application

Page 10: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Zend DiactorosPSR-7 implementation

Page 11: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Node http.Server using Diactoros

$server = \Zend\Diactoros\Server::createServer(

function ($request, $response, $done) {

return $response->getBody()->write('hello world');

},

$_SERVER,

$_GET,

$_POST,

$_COOKIE,

$_FILES

);

$server->listen();

Page 12: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Layers of an Expressive application

Expressive

Stratigility

Diactoros

PSR-7 Interface

DIRouter Template

Your Application

Page 13: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Zend StratigilityCreating & dispatching middleware pipelines

Page 14: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

So what is “middleware”?

Page 15: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Middleware in the middle

function(Request $request, RequestHandler $handler) : Response

{

// ... some code before ...

$response = $handler->handle($request);

// ... some code after ...

return $response;

}

Page 16: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Some people call it an onion

SessionInitialisingMiddleware

AuthenticationMiddleware

ThingyMiddleware

DashboardHandler

Page 17: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Some people call it an onion

SessionInitialisingMiddleware

AuthenticationMiddleware

ThingyMiddleware

DashboardHandler

Page 18: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Some people call it an onion

SessionInitialisingMiddleware

AuthenticationMiddleware

ThingyMiddleware

DashboardHandler

Page 19: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

psr/http-server-middleware

Page 20: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Middleware using MiddlewareInterface

<?php

declare(strict_types=1);

namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;

use Psr\Http\Message\ServerRequestInterface;

use Psr\Http\Server\MiddlewareInterface;

use Psr\Http\Server\RequestHandlerInterface;

final class MyMiddleware implements MiddlewareInterface

{

public function process(

ServerRequestInterface $request,

RequestHandlerInterface $requestHandler

) : ResponseInterface {

return $requestHandler>handle($request);

}

}

Page 21: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Double-pass middleware

public function __invoke(

Request $request,

Response $response,

callable $next

): Response {

return $next($request, $response);

}

!!! DEPRECATED !!!

Page 22: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Modifying the response

function(Request $request, RequestHandler $handler) : Response

{

$response = $handler->handle($request);

return $response->withHeader(

'X-Clacks-Overhead',

'GNU Terry Pratchett'

);

}

Page 23: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Pipe all the things!

$pipe = new \Zend\Stratigility\MiddlewarePipe();

$pipe->pipe($logUncaughtErrorsMiddleware);

$pipe->pipe($sessionInitialisingMiddleware);

$pipe->pipe($authenticationMiddleware);

$pipe->pipe('/', $indexHandlerMiddleware);

$pipe->pipe(new NotFoundHandler(...));

Page 24: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

LogErrorsCaughtMiddleware

function(Request $request, RequestHandler $handler) : Response

{

try {

return $handler->handle($request);

} catch (\Throwable $throwable) {

// Log the error, handle it with error page etc.

return new JsonResponse(

[

'message' => $throwable->getMessage(),

],

500

);

}

}

Page 25: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

SessionInitialisingMiddleware

function(Request $request, RequestHandler $handler) : Response

{

session_start();

return $handler->handle($request);

}

Page 26: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

function(Request $request, RequestHandler $handler) : Response

{

if (!$this->doSomeOAuthCheck($request)) {

return new JsonResponse(

[

'message' => 'Invalid OAuth token',

],

403

);

}

return $handler->handle($request);

}

AuthenticationMiddleware

Page 27: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

IndexHandlerMiddleware

function(Request $request, RequestHandler $handler) : Response

{

// ... some code ...

return new JsonResponse($someData, 200);

}

Page 28: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Layers of an Expressive application

Expressive

Stratigility

Diactoros

PSR-7 Interface

DIRouter Template

Your Application

Page 29: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Zend ExpressiveOne Ring to bring them all and in the darkness bind them.

Page 30: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Routing

Page 31: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

container-interop

Page 32: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Optionally, templating

Page 33: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Piping and Routing

Page 34: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Zend Framework 2/3What of them?

Page 35: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Middleware vs MVC

Page 36: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Using ZF componentsin Expressive

Page 37: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

ZF’s Module.php

class Module

{

public function getConfig()

{

return include __DIR__ . '/../config/module.config.php';

}

}

Page 38: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

ConfigProvider

Page 39: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

ConfigProvider

namespace Zend\Form;

class ConfigProvider

{

public function __invoke()

{

return [

'dependencies' => $this->getDependencyConfig(),

'view_helpers' => $this->getViewHelperConfig(),

];

}

}

Page 40: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

ConfigProvider#getDependencyConfig()

public function getDependencyConfig()

{

return [

'abstract_factories' => [

FormAbstractServiceFactory::class,

],

'aliases' => [

'Zend\Form\Annotation\FormAnnotationBuilder' => 'FormAnnotationBuilder',

Annotation\AnnotationBuilder::class => 'FormAnnotationBuilder',

FormElementManager::class => 'FormElementManager',

],

'factories' => [

'FormAnnotationBuilder' => Annotation\AnnotationBuilderFactory::class,

'FormElementManager' => FormElementManagerFactory::class,

],

Page 41: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Zend\Form’s Module.php (for Zend Framework)

class Module

{

public function getConfig()

{

$provider = new ConfigProvider();

return [

'service_manager' => $provider->getDependencyConfig(),

'view_helpers' => $provider->getViewHelperConfig(),

];

}

}

Page 42: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

config/config.php

<?php

$aggregator = new ConfigAggregator([

\Zend\Form\ConfigProvider::class,

// .. other config ...

], $cacheConfig['config_cache_path']);

return $aggregator->getMergedConfig();

Page 43: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

ConfigAggregator

Page 44: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

config/config.php

$aggregator = new ConfigAggregator([

\Zend\Expressive\Router\FastRouteRouter\ConfigProvider::class,

\Zend\HttpHandlerRunner\ConfigProvider::class,

new ArrayProvider($cacheConfig),

\Zend\Expressive\Helper\ConfigProvider::class,

\Zend\Expressive\ConfigProvider::class,

\Zend\Expressive\Router\ConfigProvider::class,

\App\ConfigProvider::class,

new PhpFileProvider(realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php'),

new PhpFileProvider(realpath(__DIR__) . '/development.config.php'),

], $cacheConfig['config_cache_path']);

Page 45: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Layers of an Expressive application

Expressive

Stratigility

Diactoros

PSR-7 Interface

DIRouter Template

Your Application

Page 46: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Getting startedwith Zend Expressive

Page 47: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

https://github.com/asgrim/book-library

Page 48: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive Skeleton

Page 49: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - start

composer create-project zendframework/zend-expressive-skeleton:3.0.0-rc1 book-library

Installing zendframework/zend-expressive-skeleton (3.0.0rc1)

- Installing zendframework/zend-expressive-skeleton (3.0.0rc1): Downloading (100%)

Created project in test

> ExpressiveInstaller\OptionalPackages::install

Setting up optional packages

Setup data and cache dir

Removing installer development dependencie

Page 50: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - structure

What type of installation would you like?

[1] Minimal (no default middleware, templates, or assets; configuration only)

[2] Flat (flat source code structure; default selection)

[3] Modular (modular source code structure; recommended)

Make your selection (2): 2

- Copying src/App/ConfigProvider.php

Page 51: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Modular structurezend-config-aggregator

Page 52: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Modular structurezend-config-aggregator

Page 53: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Flat or Modular?

Page 54: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Default modular structure

src/ MyModule/ src/ ConfigProvider.php Handler/ Entity/ Middleware/ templates/ test/

Page 55: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - container?

Which container do you want to use for dependency injection?

[1] Aura.Di

[2] Pimple

[3] zend-servicemanager

[4] Auryn

[5] Symfony DI Container

Make your selection or type a composer package name and version (zend-servicemanager):

- Adding package zendframework/zend-servicemanager (^3.3)

- Copying config/container.php

Page 56: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - router?

Which router do you want to use?

[1] Aura.Router

[2] FastRoute

[3] zend-router

Make your selection or type a composer package name and version (FastRoute):

- Adding package zendframework/zend-expressive-fastroute (^3.0.0alpha1)

- Whitelist package zendframework/zend-expressive-fastroute

- Copying config/routes.php

Page 57: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - template?

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):

Page 58: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - whoops?

Which error handler do you want to use during development?

[1] Whoops

[n] None of the above

Make your selection or type a composer package name and version (Whoops): n

Page 59: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Expressive installer - run it!

$ composer serve

> php -S 0.0.0.0:8080 -t public/ public/index.php

[Thu Sep 1 20:29:33 2016] 127.0.0.1:48670 [200]: /favicon.ico

{ "welcome": "Congratulations! You have installed the zend-expressive skeleton application.", "docsUrl": "https://docs.zendframework.com/zend-expressive/"}

Page 60: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Create the endpoints

Page 61: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Book entity

class Book

{

/**

* @var string

*/

private $id;

/**

* @var bool

*/

private $inStock = true;

public function __construct()

{

$this->id = (string)Uuid::uuid4();

}

Page 62: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Book entity

class Book

{

/**

* @return void

* @throws \App\Entity\Exception\BookNotAvailable

*/

public function checkOut()

{

if (!$this->inStock) {

throw Exception\BookNotAvailable::fromBook($this);

}

$this->inStock = false;

}

Page 63: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Book entity

class Book

{

/**

* @return void

* @throws \App\Entity\Exception\BookAlreadyStocked

*/

public function checkIn()

{

if ($this->inStock) {

throw Exception\BookAlreadyStocked::fromBook($this);

}

$this->inStock = true;

}

Page 64: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

FindBookByUuidInterface

interface FindBookByUuidInterface

{

/**

* @param UuidInterface $slug

* @return Book

* @throws Exception\BookNotFound

*/

public function __invoke(UuidInterface $slug): Book;

}

Page 65: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

CheckOutHandler

public function process(ServerRequestInterface $request, RequestHandler $handler): JsonResponse{ try { $book = $this->findBookByUuid->__invoke(Uuid::fromString($request->getAttribute('id'))); } catch (BookNotFound $bookNotFound) { return new JsonResponse(['info' => $bookNotFound->getMessage()], 404); }

try { $book->checkOut(); } catch (BookNotAvailable $bookNotAvailable) { return new JsonResponse(['info' => $bookNotAvailable->getMessage()], 423); }

return new JsonResponse([ 'info' => sprintf('You have checked out %s', $book->getId()), ]);}

Page 66: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

return function (

Application $app,

MiddlewareFactory $factory,

ContainerInterface $container

): void {

$app->pipe(\Zend\Stratigility\Middleware\ErrorHandler::class);

$app->pipe(\Zend\Expressive\Router\Middleware\PathBasedRoutingMiddleware::class); // Routing

$app->pipe(\Zend\Expressive\Router\Middleware\DispatchMiddleware::class); // Dispatch

$app->pipe(\Zend\Expressive\Handler\NotFoundHandler::class);

};

Define application pipeline - pipeline.php

Page 67: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

return function (

Application $app,

MiddlewareFactory $factory,

ContainerInterface $container

): void {

$app->get(

'/book/{id}/check-out',

\App\Handler\CheckOutHandler::class,

'check-out'

);

$app->get(

'/book/{id}/check-in',

\App\Handler\CheckInHandler::class,

'check-in'

);

};

Define routes - routes.php

Page 68: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Adding some ORM

Page 69: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Your application

Doctrine quick overview

DBDBAL ORM

(EntityManager)Entities

Finders,Services,

...

Page 70: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

container-interop-doctrine

Page 71: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Installation

$ composer require dasprid/container-interop-doctrine

Using version ^1.1 for dasprid/container-interop-doctrine

./composer.json has been updated

Loading composer repositories with package information

Updating dependencies (including require-dev)

Package operations: 9 installs, 0 updates, 0 removals

- Installing doctrine/lexer (v1.0.1): Loading from cache

- Installing doctrine/inflector (v1.3.0): Loading from cache

- Installing doctrine/collections (v1.5.0): Loading from cache

- Installing doctrine/cache (v1.7.1): Loading from cache

- Installing doctrine/annotations (v1.6.0): Loading from cache

- Installing doctrine/common (v2.8.1): Loading from cache

- Installing doctrine/dbal (v2.6.3): Loading from cache

- Installing doctrine/orm (v2.6.1): Loading from cache

- Installing dasprid/container-interop-doctrine (1.1.0): Loading from cache

Writing lock file

Generating autoload files

Page 72: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

src/App/ConfigProvider.php

use Doctrine\ORM\EntityManagerInterface;

use ContainerInteropDoctrine\EntityManagerFactory;

final class ConfigProvider

{

// ...

public function getDependencies() : array

{

return [

'factories' => [

EntityManagerInterface::class => EntityManagerFactory::class,

// ... other services

],

];

Page 73: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

'doctrine' => [

'connection' => [

'orm_default' => [

'driver_class' => PDOPgSql\Driver::class,

'params' => [

'url' => 'postgres://user:pass@localhost/book_library',

],

],

],

'driver' => [

'orm_default' => [

'class' => MappingDriverChain::class,

'drivers' => [

// ... and so on ...

config/autoload/doctrine.global.php

Page 74: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

'doctrine' => [

'connection' => [

'orm_default' => [

'driver_class' => PDOPgSql\Driver::class,

'params' => [

'url' => 'postgres://user:pass@localhost/book_library',

],

],

],

'driver' => [

'orm_default' => [

'class' => MappingDriverChain::class,

'drivers' => [

// ... and so on ...

config/autoload/doctrine.global.php

Page 75: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

<?php

declare(strict_types = 1);

use Doctrine\ORM\EntityManagerInterface;

use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;

use Symfony\Component\Console\Helper\HelperSet;

$container = require __DIR__ . '/container.php';

return new HelperSet([

'em' => new EntityManagerHelper(

$container->get(EntityManagerInterface::class)

),

]);

config/cli-config.php

Page 76: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Annotating the Entities

Page 77: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

/**

* @ORM\Entity

* @ORM\Table(name="book")

*/

class Book

{

/**

* @ORM\Id

* @ORM\Column(name="id", type="guid")

* @ORM\GeneratedValue(strategy="NONE")

* @var string

*/

private $id;

src/App/Entity/Book.php

Page 78: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

/**

* @ORM\Entity

* @ORM\Table(name="book")

*/

class Book

{

/**

* @ORM\Id

* @ORM\Column(name="id", type="guid")

* @ORM\GeneratedValue(strategy="NONE")

* @var string

*/

private $id;

src/App/Entity/Book.php

Page 79: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

public function __invoke(UuidInterface $id): Book

{

/** @var Book|null $book */

$book = $this->repository->find((string)$id);

if (null === $book) {

throw Exception\BookNotFound::fromUuid($id);

}

return $book;

}

src/App/Service/Book/DoctrineFindBookByUuid.php

Page 80: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

try {

$this->entityManager->transactional(function () use ($book) {

$book->checkOut();

});

} catch (BookNotAvailable $bookNotAvailable) {

return new JsonResponse(['info' => $bookNotAvailable->getMessage()], 423);

}

src/App/Handler/CheckOutHandler.php

Page 81: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Generate the schema

$ vendor/bin/doctrine orm:schema-tool:create

ATTENTION: This operation should not be executed in a production

environment.

Creating database schema...

Database schema created successfully!

$

Page 82: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Insert some data

INSERT INTO book (id, name, in_stock) VALUES (

'1c06bec9-adae-47c2-b411-73b1db850e6f',

'The Great Escape',

true

);

Page 83: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

/book/1c06bec9-adae-47c2-b411-.../check-out

{"info":"You have checked out The Great Escape"}

Page 84: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

/book/1c06bec9-adae-47c2-b411-.../check-in

{"info":"You have checked in The Great Escape"}

Page 85: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Automatic Flushing Middleware

Page 86: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

FlushingMiddleware

public function process(Request $request, RequestHandler $handler)

{

$response = $handler->handle($request);

if ($this->entityManager->isOpen()) {

$this->entityManager->flush();

}

return $response;

}

Page 87: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

FlushingMiddleware

public function process(Request $request, RequestHandler $handler)

{

$response = $handler->handle($request);

if ($this->entityManager->isOpen()) {

$this->entityManager->flush();

}

return $response;

}

Page 88: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

FlushingMiddleware

public function process(Request $request, RequestHandler $handler)

{

$response = $handler->handle($request);

if ($this->entityManager->isOpen()) {

$this->entityManager->flush();

}

return $response;

}

Page 89: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Add to pipeline

return function (

Application $app,

MiddlewareFactory $factory,

ContainerInterface $container

): void {

$app->pipe(\Zend\Stratigility\Middleware\ErrorHandler::class);

$app->pipe(\Zend\Expressive\Router\Middleware\PathBasedRoutingMiddleware::class); // Routing

$app->pipe(\App\Middleware\FlushingMiddleware::class);

$app->pipe(\Zend\Expressive\Router\Middleware\DispatchMiddleware::class); // Dispatch

$app->pipe(\Zend\Expressive\Handler\NotFoundHandler::class);

};

Page 90: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Doing more with middleware

Page 91: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Authentication

Page 92: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

public function process(

ServerRequestInterface $request,

RequestHandler $handler

) : Response {

$queryParams = $request->getQueryParams();

// DO NOT DO THIS IN REAL LIFE

// It's really not secure ;)

if (!array_key_exists('authenticated', $queryParams)

|| $queryParams['authenticated'] !== '1') {

return new JsonResponse(['error' => 'You are not authenticated.'], 403);

}

return $handler->handle($request);

}

Create the middleware

Page 93: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

public function process(

ServerRequestInterface $request,

RequestHandler $handler

) : Response {

$queryParams = $request->getQueryParams();

// DO NOT DO THIS IN REAL LIFE

// It's really not secure ;)

if (!array_key_exists('authenticated', $queryParams)

|| $queryParams['authenticated'] !== '1') {

return new JsonResponse(['error' => 'You are not authenticated.'], 403);

}

return $handler->handle($request);

}

Create the middleware

Page 94: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

public function process(

ServerRequestInterface $request,

RequestHandler $handler

) : Response {

$queryParams = $request->getQueryParams();

// DO NOT DO THIS IN REAL LIFE

// It's really not secure ;)

if (!array_key_exists('authenticated', $queryParams)

|| $queryParams['authenticated'] !== '1') {

return new JsonResponse(['error' => 'You are not authenticated.'], 403);

}

return $handler->handle($request);

}

Create the middleware

Page 95: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

public function process(

ServerRequestInterface $request,

RequestHandler $handler

) : Response {

$queryParams = $request->getQueryParams();

// DO NOT DO THIS IN REAL LIFE

// It's really not secure ;)

if (!array_key_exists('authenticated', $queryParams)

|| $queryParams['authenticated'] !== '1') {

return new JsonResponse(['error' => 'You are not authenticated.'], 403);

}

return $handler->handle($request);

}

Create the middleware

Page 96: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

return function (

Application $app,

MiddlewareFactory $factory,

ContainerInterface $container

): void {

$app->pipe(\Zend\Stratigility\Middleware\ErrorHandler::class);

$app->pipe(\Zend\Expressive\Router\Middleware\PathBasedRoutingMiddleware::class); // Routing

$app->pipe(\App\Middleware\FlushingMiddleware::class);

$app->pipe(\App\Middleware\AuthenticationMiddleware::class);

$app->pipe(\Zend\Expressive\Router\Middleware\DispatchMiddleware::class); // Dispatch

$app->pipe(\Zend\Expressive\Handler\NotFoundHandler::class);

};

Add middleware to pipe

Page 97: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

Helioscomposer require dasprid/helios

Page 98: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

PSR7-Sessioncomposer require psr7-sessions/storageless

Page 99: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

public function __invoke(ContainerInterface $container, $_, array $_ = null)

{

$symmetricKey = 'do-not-store-this-key-in-git-store-it-in-configuration-instead-please';

$expirationTime = 1200; // 20 minutes

return new SessionMiddleware(

new Signer\Hmac\Sha256(),

$symmetricKey,

$symmetricKey,

SetCookie::create(SessionMiddleware::DEFAULT_COOKIE)

->withSecure(false) // false on purpose, unless you have https locally

->withHttpOnly(true)

->withPath('/'),

new Parser(),

$expirationTime,

new SystemClock()

);

}

Factory the middleware

Page 100: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

return function (

Application $app,

MiddlewareFactory $factory,

ContainerInterface $container

): void {

$app->pipe(\Zend\Stratigility\Middleware\ErrorHandler::class);

$app->pipe(\Zend\Expressive\Router\Middleware\PathBasedRoutingMiddleware::class); // Routing

$app->pipe(\App\Middleware\FlushingMiddleware::class);

$app->pipe(\PSR7Sessions\Storageless\Http\SessionMiddleware::class);

$app->pipe(\App\Middleware\AuthenticationMiddleware::class);

$app->pipe(\Zend\Expressive\Router\Middleware\DispatchMiddleware::class); // Dispatch

$app->pipe(\Zend\Expressive\Handler\NotFoundHandler::class);

};

Add middleware to pipe

Page 101: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

$session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);

$session->set('counter', $session->get('counter', 0) + 1);

Session is stored in Request

Page 102: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

$skills++;

Page 103: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

@asgrim

To summarise...

● PSR-7 & PSR-15 lay the foundations!● Diactoros is just a PSR-7 implementation● Stratigility is a middleware pipeline: the main bit● Expressive is a glue for everything● ConfigProvider is great for aggregating (merging) config● container-interop-doctrine makes Doctrine work easier● Middleware all the things!● Similar concepts in other frameworks (e.g. Slim)

Page 105: Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)

Any questions?

James Titcumb@asgrim