You've heard of Zend's new framework, Expressive, and you've heard it's the new hotness. In this talk, I will introduce the concepts of Expressive, how to bootstrap a simple application with the framework using best practices, and finally how to integrate a third party tool like Doctrine ORM.
Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)
1. @asgrim
Kicking off with Zend Expressive
and Doctrine ORM
James Titcumb
ConFoo Vancouver 2017
Follow along (optional): https://github.com/asgrim/book-library
20. @asgrim
Middleware using MiddlewareInterface
<?php
declare(strict_types=1);
namespace AppMiddleware;
use InteropHttpServerMiddlewareDelegateInterface;
use InteropHttpServerMiddlewareMiddlewareInterface;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
final class MyMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
DelegateInterface $delegate
) : ResponseInterface {
return $delegate->process($request);
}
}
47. @asgrim
Expressive installer - start
$ composer create-project zendframework/zend-expressive-skeleton book-library
Installing zendframework/zend-expressive-skeleton (2.0.4)
- Installing zendframework/zend-expressive-skeleton (2.0.4): Downloading (100%)
Created project in book-library-2
> ExpressiveInstallerOptionalPackages::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies
48. @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):
53. @asgrim
Expressive installer - container?
Which container do you want to use for dependency injection?
[1] Aura.Di
[2] Pimple
[3] Zend ServiceManager
Make your selection or type a composer package name and version (Zend ServiceManager):
54. @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):
55. @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):
56. @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):
57. @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/"
}
59. @asgrim
Book entity
class Book
{
/**
* @var string
*/
private $id;
/**
* @var bool
*/
private $inStock = true;
public function __construct()
{
$this->id = (string)Uuid::uuid4();
}
60. @asgrim
Book entity
class Book
{
/**
* @return void
* @throws AppEntityExceptionBookNotAvailable
*/
public function checkOut()
{
if (!$this->inStock) {
throw ExceptionBookNotAvailable::fromBook($this);
}
$this->inStock = false;
}
61. @asgrim
Book entity
class Book
{
/**
* @return void
* @throws AppEntityExceptionBookAlreadyStocked
*/
public function checkIn()
{
if ($this->inStock) {
throw ExceptionBookAlreadyStocked::fromBook($this);
}
$this->inStock = true;
}
71. @asgrim
Installation
$ composer require dasprid/container-interop-doctrine
Using version ^1.0 for dasprid/container-interop-doctrine
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
- Installing dasprid/container-interop-doctrine (1.0.0): Loading from cache
Package http-interop/http-middleware is abandoned, you should avoid using it.
Use http-interop/http-server-middleware instead.
Writing lock file
Generating autoload files
$
81. @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!
$
82. @asgrim
Insert some data
INSERT INTO book (id, name, in_stock) VALUES (
'1c06bec9-adae-47c2-b411-73b1db850e6f',
'The Great Escape',
true
);
92. @asgrim
public function process(
ServerRequestInterface $request,
DelegateInterface $delegate
) : 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 $delegate->process($request);
}
Create the middleware
93. @asgrim
public function process(
ServerRequestInterface $request,
DelegateInterface $delegate
) : 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 $delegate->process($request);
}
Create the middleware
94. @asgrim
public function process(
ServerRequestInterface $request,
DelegateInterface $delegate
) : 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 $delegate->process($request);
}
Create the middleware
95. @asgrim
public function process(
ServerRequestInterface $request,
DelegateInterface $delegate
) : 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 $delegate->process($request);
}
Create the middleware
102. @asgrim
To summarise...
● PSR-7 is the foundation for this!
● Diactoros is just a PSR-7 implementation
● Stratigility is a middleware pipeline: the main bit
● Expressive is a glue for everything
● DoctrineModule can be used (with some fiddling)
● container-interop-doctrine makes Doctrine work easier
● Middleware all the things!
● Similar concepts in other frameworks (e.g. Slim)