Large and heavy PHP frameworks are a thing of the past. Modern PHP developers now have a wealth of libraries and packages available to perform specific tasks, and microservices are fast becoming a preferred way to architect applications. But many don't know how to start, and get thrown in the deep end to flounder. This hands-on workshop will introduce what microservices are, and how to leverage middleware to create them. We will use the Zend Expressive microframework to leverage components of Zend Framework, and other libraries, to quickly create awesome things without requiring an entire framework. Resources for reference and continued learning will also be shared.
8. 8
Zend Expressive Workshop
●
Microservice
– All the buzz is “microservices”.
– ...complex applications are composed of small, independent processes
communicating with each other using language-agnostic APIs. These
services are small building blocks, highly decoupled and focused on doing
a small task, facilitating a modular approach to system-building. –
Wikipedia
9. 9
Zend Expressive Workshop
●
But in PHP...
– How to keep microservices light?
– Microservices shouldn’t be heavy
I’m a
Microservice!!!
10. 10
Zend Expressive Workshop
●
Full Stack Frameworks Suck
– Heavy and bloated
– “Kitchen Sink”
– “You don’t have to use everything, but its there...”
11. 11
Zend Expressive Workshop
●
Need For Speed
– What does a microservice “need”?
●
HTTP message layer
●
Routing capabilities
●
Dependency injection
– Testable
– Swappable pieces
●
Templating
– Optional (APIs may not need it, except documentation)
13. 13
Zend Expressive Workshop
●
All The Things!!!
– So many tools:
Monolog
Whoops
Flysystem
IBMiToolkit
OAuth2 Server
https://github.com/ziadoz/awesome-php
15. 15
Zend Expressive Workshop
●
PSR-7 Doesn’t Suck
– Part of PHP-Fig.org recommendations
– HTTP Messages
●
Request from client to server
●
Response from server to client
– Interfaces
●
PsrHttpMessageMessageInterface
– PsrHttpMessageRequestInterface
●
PsrHttpMessageServerRequestInterface
– PsrHttpMessageResponseInterface
●
PsrHttpMessageStreamInterface
●
PsrHttpMessageUploadFileInterface
●
PsrHttpMessageUriInterface
16. 16
Zend Expressive Workshop
●
Middleware
– ...Middleware makes it easier for software developers to implement
communication and input/output, so they can focus on the specific
purpose of their application. – Wikipedia
– Lighter applications (only what is needed)
– Composed of layers
17. 17
Zend Expressive Workshop
●
Zend Expressive
– Microframework built around middleware
– Very lean runtime
– Built to consume PSR-7
– Use for building:
●
APIs
●
Web applications
●
Single page sites
– Choose your own stack
– Great documentation
●
https://zendframework.github.io/zend-expressive/
25. 25
Zend Expressive Workshop
●
Lab 01 – Install Zend Expressive
– From within the VM install Zend Expressive
●
At ‘/home/vagrant/workspace/’ delete the ‘expressive’ folder
●
Composer is globally installed in the VM, enabling easy project
creation. (stick to the defaults)
$ composer create-project zendframework/zend-expressive-
skeleton expressive
●
Verify that Zend Expressive Skeleton was properly installed.
http://localhost then click on the Expressive link.→
29. 29
Zend Expressive Workshop
●
Middleware Addition Approaches
– Currently uses a config-driven approach to creating/using middleware
●
Middleware added to services through configuration
– With version 1.1 of Zend Expressive the “recommended” will be
programmatic/explicit approach versus config-driven.
●
Middleware information driven by pipes
●
More on this later
– In this workshop the config-driven approach is used in examples
38. 38
Zend Expressive Workshop
●
Lab 02 – REST Test using HTTPie
– Within the VM
●
We will use HTTPie from the command line instead of raw cURL to
make requests.
●
Make a request to the existing ping action we analyzed:
$ http http://expressive/api/ping
●
If doing this from the host browser the URL would be different:
$ http http://expressive:8081/api/ping
●
Observe the response:
– Note the Header information
– Note the json response object
39. 39
Zend Expressive Workshop
●
Lab 02 – REST Test using HTTPie (cont’d)
– Within the VM
●
Observe the response:
– Note the Header information
– Note the json response object
43. 43
Zend Expressive Workshop
●
Header Middleware
– Add the middleware to the container
– Set it to always be included
(/config/autoload/middleware-pipeline.global.php)
45. 45
Zend Expressive Workshop
●
Lab 03 – Create a Middleware
– Create middleware to add content into ALL response headers
●
Add an appropriately named middleware class. (Example:
TheClacksMiddleware)
– Define the namespace (Example: ‘AppMiddleware’)
– Use PsrHttpMessageResponseInterface and
ServerRequestInterface.
– Return the response withHeader.
●
Add the new middleware into our middleware services. Remember we
want it to ALL responses.
●
Verify
NOTE: Refer to the expressive-final application if you need hints
47. 47
Zend Expressive Workshop
●
Database Connected Example With Zend Db
– First we need a database connection.
●
Will use Zend-Db for this example, but could be anything.
●
Composer to the rescue!
48. 48
Zend Expressive Workshop
●
Database Connected Example With Zend Db
– Specify adapter (provided by Zend/Db/ConfigProvider() in this case)
(/config/autoload/db.global.php)
49. 49
Zend Expressive Workshop
●
Database Connected Example With Zend Db
– Provide local/instance configuration
● This would be driver and credentials
● (credentials not needed with sqlite)
(/config/autoload/db.local.php)
50. 50
Zend Expressive Workshop
●
Database Connected Example With Zend Db
– Create the action (view 1 of 2 - constructor)
(/src/App/Action/UserListAction.php)
51. 51
Zend Expressive Workshop
●
Database Connected Example With Zend Db
– Create the action (view 2 of 2 - __invoke method)
(/src/App/Action/UserListAction.php cont’d)
52. 52
Zend Expressive Workshop
●
Database Connected Example With Zend Db
– Create a factory to pass items needed by the action
(/src/App/Action/UserListFactory.php)
57. 57
Zend Expressive Workshop
●
Lab 04 – Database Connected Middleware
– Create a User middleware allowing management of user records in a
database using Zend Db
●
Using Composer require dependency ‘zendframework/zend-db:2.8.*’
●
Create an autoload global config file to provide
Zend/Db/ConfigProvider
●
Create an autoload local config to provide a db container supplying
the location to the users.db Sqlite database in the /data directory
●
Add an appropriately named middleware class (Example:
UserListAction)
– Define the namespace (Example: ‘AppAction’)
– Use PsrHttpMessageResponseInterface, ServerRequestInterface,
ZendDiactorosResponseHtmlResponse,
ZendExpressiveTemplate, and ZendDbAdapterAdapter.
– Define $template and $adapter fields for those objects
58. 58
Zend Expressive Workshop
●
Lab 04 – Database Connected Middleware (Cont’d)
– Create a User middleware (Cont’d
●
Add a middleware class (Cont’d)
– Add a constructor to receive/set $template and $adapter
●
Typehint $template with TemplateTemplateRendererInterface
– Add an invoke method leveraging ServerRequestInterface,
ResponseInterface, and $next as callable.
– Using the Zend Db adapter create the query for Sqlite.
●
For Sqlite this involves defining a statement, then executing
– Return the HtmlResponse rendering the view template.
●
Add a factory class to prepare the items needed by the Action just
created
– Use InteropContainerContainerInterface,
ZendExpressiveTemplateTemplateRendererInterface, and
ZendDbAdapterAdapterInterface.
59. 59
Zend Expressive Workshop
●
Lab 04 – Database Connected Middleware (Cont’d)
– Create a User middleware (Cont’d
●
Add a factory class (Cont’d)
– Define the namespace (Example: ‘AppAction’)
– In the invoke() method typehint the $container argument using
ContainerInterface.
– Gain the $template if the $container has the
TemplateRenderInterface.
– Gain the DB $adapter also from the $container using
AdapterInterface.
– Return an instantiation of the Action class created earlier by
passing the $template and $adapter.
●
Add the factory to the dependencies in the global routes.
●
Add a route to access the new middleware
●
Create a view template to display the user results.
61. 61
Zend Expressive Workshop
●
Lab 05 – Create Moar Middleware
– Create a uuid middleware to add content into all response headers
●
Using Composer add a dependency ‘ramsey/uuid’
●
Add an appropriately named middleware class. (Example:
UuidMiddleware)
– Define the namespace (Example: ‘AppMiddleware’)
– Use PsrHttpMessageResponseInterface, ServerRequestInterface,
and RamseyUuidUuid (and maybe
RamseyUuidExceptionUnsatisfiedDependencyException).
– Return a uuid in the response withHeader.
●
Add the new middleware into our middleware services. Remember we
want it to ALL responses.
●
Verify
62. 62
Zend Expressive Workshop
●
Lab 05 – Create Moar Middleware (cont’d)
– Continuing… Create middleware to add response time to ALL response
headers
●
Add an appropriately named middleware class. (Example:
RequestTimeMiddleware)
– Define the namespace (Example: ‘AppMiddleware’)
– Use PsrHttpMessageResponseInterface and
ServerRequestInterface.
– Create code returning the time the request took
– Return the response withHeader.
●
Add the new middleware into our middleware services. Remember we
want it to ALL responses.
●
Verify
NOTE: Refer to the expressive-final application if you need hints
64. 64
Zend Expressive Workshop
●
Database Connected Example With Doctrine
– First we need a database connection.
●
Will use Doctrine DBAL for this example, but could be anything.
●
Composer to the rescue!
65. 65
Zend Expressive Workshop
●
Database Connected Example With Doctrine
– Provide local/instance configuration
● This would be driver and credentials
● (credentials not needed with sqlite)
(/config/autoload/dbal.local.php)
66. 66
Zend Expressive Workshop
●
Database Connected Example With Doctrine
– Create the action (view 1 of 2 - constructor)
(/src/App/Action/UserDbalListAction.php)
67. 67
Zend Expressive Workshop
●
Database Connected Example With Doctrine
– Create the action (view 2 of 2 - __invoke method)
(/src/App/Action/UserDbalListAction.php cont’d)
68. 68
Zend Expressive Workshop
●
Database Connected Example With Doctrine
– Create a factory to pass items needed by the action
(/src/App/Action/UserDbalListFactory.php)
69. 69
Zend Expressive Workshop
●
Database Connected Example With Doctrine
– Add the new action to dependencies, as shown below for the previous
action, but with the new namespace for this example
(/config/autoload/routes.global.php)
73. 73
Zend Expressive Workshop
●
Lab 06 – Database Connected Middleware
– Create a User middleware allowing management of user records in a
database using Doctrine Dbal
●
Using Composer require dependency ‘doctrinedbal:2.5.*’
●
Create an autoload local config to provide a doctrine-connection
container supplying the location to the users.db sqlite database in
the /data directory
●
Add an appropriately named middleware class (Example:
UserDbalListAction)
– Define the namespace (Example: ‘AppAction’)
– Use PsrHttpMessageResponseInterface, ServerRequestInterface,
ZendDiactorosResponseHtmlResponse, and
ZendExpressiveTemplate.
– Define $template and $connection fields for those objects
74. 74
Zend Expressive Workshop
●
Lab 06 – Database Connected Middleware (Cont’d)
– Create a User middleware (Cont’d
●
Add a middleware class (Cont’d)
– Add a constructor to receive/set $template and $connection
●
Typehint $template with TemplateTemplateRendererInterface
– Add an invoke method leveraging ServerRequestInterface,
ResponseInterface, and $next as callable.
– Using the Doctrine $connection create the query for Sqlite.
– Return the HtmlResponse rendering the view template.
●
Add a factory class to prepare the items needed by the Action just
created
– Use InteropContainerContainerInterface,
ZendExpressiveTemplateTemplateRendererInterface, and
DoctrineDBALDriverManager.
75. 75
Zend Expressive Workshop
●
Lab 06 – Database Connected Middleware (Cont’d)
– Create a User middleware (Cont’d
●
Add a factory class (Cont’d)
– Define the namespace (Example: ‘AppAction’)
– In the invoke() method typehint the $container argument using
ContainerInterface.
– Gain the $template if the $container has the
TemplateRenderInterface.
– Define the DB $credentials also from the $container and kick off
Doctrine to return the $connection to users for the view to use.
– Return an instantiation of the Action class created earlier by
passing the $template and $connection.
●
Add the factory to the dependencies in the global routes.
●
Add a route to access the new middleware
●
Create a view template to display the user results.
77. 77
Zend Expressive Workshop
●
Zend Expressive Skeleton Programmatic
– Version 1.1 of Zend Expressive “recommended” approach to adding more
middleware will be with a programmatic/explicit approach.
●
In Github the repo for expressive-final has an additional branch
(name: programmatic) created by Matthew Weier O’Phinney, from the
Zend Expressive team, showing the programmatic approach to
everything in this workshop.
●
https://github.com/adamculp/expressive-workshop
78. 78
Zend Expressive Workshop
●
Resources
– Zend Expressive Site - http://zendframework.github.io/zend-expressive/
– MasterZendFramework - http://www.masterzendframework.com
– Oscar Otero’s list https://github.com/oscarotero/psr7-middlewares
– This github repo https://github.com/adamculp/expressive-workshop
– Slides - http://www.slideshare.net/adamculp/zend-expressive-workshop
– Code used for the workshop - https://github.com/adamculp/expressive-
workshop
– More to come!
79. 79
Zend Expressive Workshop
●
With Zend Expressive:
– Easy to build middleware
– Lightweight, add what is really needed
– Fast – no extra load
– Microservices in PHP are better