by Enrico Zimuel / @ezimuel
Senior Software Engineer
Zend Technologies, a Rogue Wave Company
Oct 18, ZendCon 2016, Las Vegas
|
GET /path HTTP/1.1
Host: example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{"foo":"bar"}
But every framework does it differently.
$method = $request->getMethod();
$method = $request->getRequestMethod();
$method = $request->method;
$method = $request->getMethod();
$accept = $request->getHeader('Accept');
$path = $request->getUri()->getPath();
$controller = $request->getAttribute('controller');
$response->getBody()->write('Hello world!');
$response = $response->withStatus(200, 'OK')
->withHeader('Content-Type', 'text/plain');
A function that gets a request and generates a response
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
function (Request $request, Response $response) {
// manipulate $request to generate a $response
return $response;
}
Use an additional callable during the invoke ($next)
class Middleware
{
public function __invoke(
\Psr\Http\Message\ServerRequestInterface $request,
\Psr\Http\Message\ResponseInterface $response,
callable $next = null
) {
// do something before
if ($next) {
$next($request, $response);
}
// do something after
return $response;
}
}
function ($request, $response, $next)
use Zend\Expressive\AppFactory;
chdir(dirname(__DIR__));
require 'vendor/autoload.php';
$app = AppFactory::create();
$app->get('/', function ($request, $response, $next) {
$response->getBody()->write('Hello, world!');
return $response;
});
$app->pipeRoutingMiddleware();
$app->pipeDispatchMiddleware();
$app->run();
namespace Zend\Expressive\Router;
use Psr\Http\Message\ServerRequestInterface as Request;
interface RouterInterface
{
public function addRoute(Route $route);
public function match(Request $request);
public function generateUri($name, array $substitutions = []);
}
// $app is an instance of Zend\Expressive\AppFactory
$app->get('/', function ($request, $response, $next) {
$response->getBody()->write('Hello, world!');
return $response;
});
// $app is an instance of Zend\Expressive\AppFactory
// Executed in all the requests
$app->pipe($apiMiddleware);
$app->pipe('middleware service name');
// Pipe to a specific URL
$app->pipe('/api', $apiMiddleware);
$app->pipe('/api', 'middleware service name');
// Error handler
$app->pipeErrorHandler('error handler service name');
$app->pipeErrorHandler('/api', 'error handler service name');
use Zend\Expressive\AppFactory;
use Zend\ServiceManager\ServiceManager;
$container = new ServiceManager();
$container->setFactory('HelloWorld', function ($container) {
return function ($request, $response, $next) {
$response->write('Hello, world!');
return $response;
};
});
$app = AppFactory::create($container);
$app->get('/', 'HelloWorld');
We support container-interop
namespace Zend\Expressive\Template;
interface TemplateRendererInterface
{
public function render($name, $params = []);
public function addPath($path, $namespace = null);
public function getPaths();
public function addDefaultParam($templateName, $param, $value);
}
use Zend\Expressive\Application;
use Zend\Expressive\Plates\PlatesRenderer;
use Zend\Expressive\TemplatedErrorHandler as TErrHandler;
$plates = new PlatesRenderer();
$plates->addPath(__DIR__ . '/templates/error', 'error');
$final = new TErrHandler($plates, 'error::404', 'error::500');
$app = new Application($router, $container, $final);
Use Vagrant to set up the environment.
Clone the repository ezimuel/zend-expressive-workshop
git clone https://github.com/ezimuel/zend-expressive-workshop
Run composer:
cd zend-expressive-workshop
composer install
Turn on Vagrant:
vagrant up
The PHP server runs at localhost:8080
├── config │ └── autoload ├── data │ └── cache ├── public ├── src │ └── App │ └── Action ├── templates │ ├── app │ ├── error │ └── layout └── test
The application configuration files, including:
public/index.php (programmatic version)
$container = require 'config/container.php';
$app = $container->get(Application::class);
// Pipeline
$app->pipe(Helper\ServerUrlMiddleware::class);
// here add custom middleware ...
$app->pipeRoutingMiddleware();
$app->pipe(Helper\UrlHelperMiddleware::class);
$app->pipeDispatchMiddleware();
// Routes
$app->get('/', Action\HomePageAction::class, 'home');
$app->get('/api/ping', Action\PingAction::class, 'api.ping');
$app->run();
src/App/Action/HomePageFactory.php
class HomePageFactory
{
public function __invoke(ContainerInterface $container)
{
$router = $container->get(RouterInterface::class);
$template = ($container->has(TemplateRendererInterface::class))
? $container->get(TemplateRendererInterface::class)
: null;
return new HomePageAction($router, $template);
}
}
src/App/Action/HomePageAction.php
class HomePageAction
{
private $router;
private $template;
public function __construct(
Router\RouterInterface $router,
Template\TemplateRendererInterface $template = null
){
$this->router = $router;
$this->template = $template;
}
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next = null
){
$data = [];
// insert value into $data
return new HtmlResponse($this->template->render(
'app::home-page',
$data
));
}
}
You can check out a solution in exercise1 branch:
git checkout exercise1
We use a Model layer to interact with the database
We built a Speaker and Talk classes in src/App/Model
You can check out a solution in exercise2 branch:
git checkout exercise2
You can check out a solution in exercise3 branch:
git checkout exercise3
Please rate this workshop at:
https://legacy.joind.in/19407