1. Dependencies and Directories
// We'll need a few dependencies
composer require zendframework/zend-expressive \
zendframework/zend-expressive-fastroute \
zendframework/zend-servicemanager \
&& mkdir -p public \
&& touch public/index.php
2. The Bootstrap File
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;
});
// Setup routing and dispatching middleware
$app->pipeRoutingMiddleware();
$app->pipeDispatchMiddleware();
$app->run();
First - Refactor The Handler
// src/App/HelloWorldAction.php
namespace App;
class HelloWorldAction
{
public function __invoke($request, $response, $next)
{
$response->getBody()->write('Hello, world!');
return $response;
}
}
Next - Refactor index.php
use Zend\ServiceManager\ServiceManager;
$container = new ServiceManager();
$container->setInvokableClass(
\App\HelloWorldAction::class
);
$app = AppFactory::create($container);
$app->get('/', \App\HelloWorldAction::class);
1. Add further dependencies
composer require zendframework/zend-config \
zendframework/zend-stdlib;
2. Add Configuration Files
// Create further configuration files
mkdir -p config/autoload;
touch config/autoload/dependencies.global.php \
config/autoload/routes.global.php \
config/container.php \
config/config.php;
3. Configure Dependencies
// dependencies.global.php
use Zend\ServiceManager\Factory\InvokableFactory;
use \Zend\Expressive\Container\ApplicationFactory;
use \Zend\Expressive\Application;
use \App\HelloWorldAction;
return [
'dependencies' => [
'factories' => [
Application::class => ApplicationFactory::class,
HelloWorldAction::class => InvokableFactory::class
],
]
];
4. Configure Routes
// routes.global.php
return [
'routes' => [
[
'path' => '/',
'middleware' => \App\HelloWorldAction::class,
'allowed_methods' => [ 'GET' ],
],
],
];
5. Simplify Config Retrieval
// config.php
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\Glob;
$config = [];
foreach (Glob::glob(
'config/autoload/{{,*.}global,{,*.}local}.php',
Glob::GLOB_BRACE) as $file
) {
$config = ArrayUtils::merge($config, include $file);
}
return new ArrayObject($config, ArrayObject::ARRAY_AS_PROPS);
6. Configure the DI Container
// container.php
use Zend\ServiceManager\Config;
use Zend\ServiceManager\ServiceManager;
// Load configuration
$config = require __DIR__.'/config.php';
// Build container
$container = new ServiceManager();
(new Config($config['dependencies']))
->configureServiceManager($container);
// Inject config
$container->setService('config', $config);
return $container;
Then Refactor index.php - again
// Retrieve the application from the container
$container = include 'config/container.php';
$app = $container->get(\Zend\Expressive\Application::class);
What Kind of Application?
Minimal skeleton?
(no default middleware, templates, or assets; configuration only)
[y] Yes (minimal)
[n] No (full; recommended)
Make your selection (No):
Which 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):
Which DI 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):
Which Template Engine?
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):
An Error Handler?
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):
1. Update Dependencies
use Zend\Db\Adapter\{AdapterServiceFactory, Adapter};
return [
'dependencies' => [
'factories' => [
Adapter::class => AdapterServiceFactory::class,
],
],
];
2. Add Its Configuration
// config/autoload/database.global.php
return [
'db' => [
'driver' => 'Pdo',
'dsn' => 'mysql:host=mysql;port=3306;dbname=project',
'user' => 'project',
'password' => 'project'
]
];
The Middleware Class
public function __invoke(ServerRequestInterface $request,
ResponseInterface $response,
callable $next
) {
$session = $request->getAttribute(
SessionMiddleware::SESSION_ATTRIBUTE
);
if ($session->get('id') === null) {
$route = sprintf(
'/login?redirect_to=%s',
$this->getCurrentRequest($request)
)
return new RedirectResponse($route, 302);
}
return $next($request, $response);
}
The Middleware Class
public function __invoke(ServerRequestInterface $request,
ResponseInterface $response,
callable $next = null)
{
$session = $request->getAttribute(
SessionMiddleware::SESSION_ATTRIBUTE
);
$validates = $this->doValidation($request, $session);
$user = $this->form->getData();
The Middleware Class
if ($request->getMethod() === 'POST' && $validates) {
// May throw an exception...
$userId = $this->userAuthenticationService
->authenticateUser(
$user->getUsername(),
$user->getPassword()
);
$session->set('id', $userId);
return new RedirectResponse(
$this->getRedirectUri($request),
RFC7231::FOUND
);
}
The Middleware Class
return new HtmlResponse(
$this->template->render(self::PAGE_TEMPLATE, [
'form' => $this->form,
])
);
}
Initialising It
public function __invoke(ContainerInterface $container) {
$router = $container->get(RouterInterface::class);
$template = $container->get(TemplateRendererInterface::class);
$userRepository = $container->get(
UserAuthenticationInterface::class
);
$userEntity = new LoginUser();
return new LoginPageAction(
$router,
$template,
$userRepository,
$userEntity,
);
}
Registering Dependencies
return [
'dependencies' => [
'factories' => [
AuthenticationMiddleware::class => AuthenticationMiddlewareFactory::class,
LoginPageAction::class => LoginPageFactory::class,
],
]
]
Enabled For One Route
[
'name' => 'home',
'path' => '/',
'middleware' =>
[
\App\Middleware\AuthenticationMiddleware::class,
App\Action\HomePageAction::class,
],
'allowed_methods' => ['GET'],
],
[
'name' => 'login',
'path' => '/login',
'middleware' => App\Action\LoginPageAction::class,
'allowed_methods' => ['GET', 'POST'],
],
Enabled For All Routes
// middleware-pipeline.global.php
'routing' => [
'middleware' => [
ApplicationFactory::ROUTING_MIDDLEWARE,
\App\Middleware\AuthenticationMiddleware::class,
ApplicationFactory::DISPATCH_MIDDLEWARE,
],
'priority' => 1,
],