{"id":3722,"date":"2019-03-12T03:14:58","date_gmt":"2019-03-12T03:14:58","guid":{"rendered":"http:\/\/myprojects.advchaweb.com\/?p=3722"},"modified":"2019-03-12T14:13:40","modified_gmt":"2019-03-12T14:13:40","slug":"zend-framework-3-zend-expressive","status":"publish","type":"post","link":"https:\/\/myprojects.advchaweb.com\/index.php\/2019\/03\/12\/zend-framework-3-zend-expressive\/","title":{"rendered":"Zend Framework 3: Zend Expressive"},"content":{"rendered":"<p>Ref: https:\/\/docs.zendframework.com\/zend-expressive\/<br \/>\nhttps:\/\/docs.zendframework.com\/zend-expressive\/v3\/getting-started\/quick-start\/<br \/>\n<a href=\"https:\/\/samsonasik.wordpress.com\/2018\/01\/12\/create-login-functionality-in-expressive-3\/\">Create Login functionality in Expressive&nbsp;3<\/a><\/p>\n<p>Install via composer:<\/p>\n<pre class=\"lang:default decode:true \">teddy@teddy:~\/Documents\/works$ composer create-project zendframework\/zend-expressive-skeleton\r\nInstalling zendframework\/zend-expressive-skeleton (3.2.3)\r\n  - Installing zendframework\/zend-expressive-skeleton (3.2.3): Downloading (connDownloading (100%)         \r\nCreated project in \/home\/teddy\/Documents\/works\/zend-expressive\/zend-expressive-skeleton\r\n&gt; ExpressiveInstaller\\OptionalPackages::install\r\nSetting up optional packages\r\nSetup data and cache dir\r\nRemoving installer development dependencies\r\n\r\n  What type of installation would you like?\r\n  [1] Minimal (no default middleware, templates, or assets; configuration only)\r\n  [2] Flat (flat source code structure; default selection)\r\n  [3] Modular (modular source code structure; recommended)\r\n  Make your selection (2): \r\n  - Copying src\/App\/ConfigProvider.php\r\n\r\n  Which container do you want to use for dependency injection?\r\n  [1] Aura.Di\r\n  [2] Pimple\r\n  [3] zend-servicemanager\r\n  [4] Auryn\r\n  [5] Symfony DI Container\r\n  [6] PHP-DI\r\n  Make your selection or type a composer package name and version (zend-servicemanager): \r\n  - Adding package zendframework\/zend-servicemanager (^3.3)\r\n  - Copying config\/container.php\r\n\r\n  Which router do you want to use?\r\n  [1] Aura.Router\r\n  [2] FastRoute\r\n  [3] zend-router\r\n  Make your selection or type a composer package name and version (FastRoute): \r\n  - Adding package zendframework\/zend-expressive-fastroute (^3.0)\r\n  - Whitelist package zendframework\/zend-expressive-fastroute\r\n  - Copying config\/routes.php\r\n\r\n  Which template engine do you want to use?\r\n  [1] Plates\r\n  [2] Twig\r\n  [3] zend-view installs zend-servicemanager\r\n  [n] None of the above\r\n  Make your selection or type a composer package name and version (n): 1\r\n  - Adding package zendframework\/zend-expressive-platesrenderer (^2.0)\r\n  - Whitelist package zendframework\/zend-expressive-platesrenderer\r\n  - Copying templates\/error\/404.phtml\r\n  - Copying templates\/error\/error.phtml\r\n  - Copying templates\/layout\/default.phtml\r\n  - Copying templates\/app\/home-page.phtml\r\n\r\n  Which error handler do you want to use during development?\r\n  [1] Whoops\r\n  [n] None of the above\r\n  Make your selection or type a composer package name and version (Whoops): \r\n  - Adding package filp\/whoops (^2.1.12)\r\n  - Copying config\/autoload\/development.local.php.dist\r\nRemove installer\r\nRemoving composer.lock from .gitignore\r\nRemoving Expressive installer classes, configuration, tests and docs\r\nLoading composer repositories with package information\r\nUpdating dependencies (including require-dev)\r\nPackage operations: 64 installs, 0 updates, 0 removals\r\n  - Installing zendframework\/zend-component-installer (2.1.1): Downloading (connDownloading (100%)         \r\n  - Installing ocramius\/package-versions (1.4.0): Downloading (100%)         \r\n  - Installing zendframework\/zend-escaper (2.6.0): Loading from cache\r\n  - Installing zendframework\/zend-expressive-template (2.0.0): Downloading (connDownloading (100%)         \r\n  - Installing psr\/http-message (1.0.1): Loading from cache\r\n  - Installing psr\/http-server-handler (1.0.1): Downloading (100%)         \r\n  - Installing psr\/http-server-middleware (1.0.1): Downloading (100%)         \r\n  - Installing psr\/container (1.0.0): Loading from cache\r\n  - Installing fig\/http-message-util (1.1.3): Downloading (100%)         \r\n  - Installing zendframework\/zend-expressive-router (3.1.0): Downloading (connecDownloading (100%)         \r\n  - Installing zendframework\/zend-expressive-helpers (5.1.3): Downloading (conneDownloading (100%)         \r\n  - Installing league\/plates (3.3.0): Downloading (100%)         \r\n  - Installing zendframework\/zend-expressive-platesrenderer (2.0.0): DownloadingDownloading (100%)         \r\n    Installing Zend\\Expressive\\Plates\\ConfigProvider from package zendframework\/zend-expressive-platesrenderer\r\n  - Installing roave\/security-advisories (dev-master 4e04718)\r\n  - Installing zendframework\/zend-stdlib (3.2.1): Downloading (100%)         \r\n  - Installing zendframework\/zend-config-aggregator (1.1.1): Downloading (connecDownloading (100%)         \r\n  - Installing psr\/http-factory (1.0.0): Downloading (100%)         \r\n  - Installing container-interop\/container-interop (1.2.0): Loading from cache\r\n  - Installing zendframework\/zend-servicemanager (3.4.0): Downloading (connectinDownloading (100%)         \r\n  - Installing nikic\/fast-route (v1.3.0): Loading from cache\r\n  - Installing zendframework\/zend-expressive-fastroute (3.0.2): Downloading (conDownloading (100%)         \r\n    Installing Zend\\Expressive\\Router\\FastRouteRouter\\ConfigProvider from package zendframework\/zend-expressive-fastroute\r\n  - Installing sebastian\/version (2.0.1): Loading from cache\r\n  - Installing sebastian\/resource-operations (2.0.1): Loading from cache\r\n  - Installing sebastian\/recursion-context (3.0.0): Loading from cache\r\n  - Installing sebastian\/object-reflector (1.1.1): Loading from cache\r\n  - Installing sebastian\/object-enumerator (3.0.3): Loading from cache\r\n  - Installing sebastian\/global-state (2.0.0): Loading from cache\r\n  - Installing sebastian\/exporter (3.1.0): Loading from cache\r\n  - Installing sebastian\/environment (4.1.0): Loading from cache\r\n  - Installing sebastian\/diff (3.0.2): Loading from cache\r\n  - Installing sebastian\/comparator (3.0.2): Loading from cache\r\n  - Installing phpunit\/php-timer (2.1.1): Loading from cache\r\n  - Installing phpunit\/php-text-template (1.2.1): Loading from cache\r\n  - Installing phpunit\/php-file-iterator (2.0.2): Loading from cache\r\n  - Installing theseer\/tokenizer (1.1.0): Loading from cache\r\n  - Installing sebastian\/code-unit-reverse-lookup (1.0.1): Loading from cache\r\n  - Installing phpunit\/php-token-stream (3.0.1): Loading from cache\r\n  - Installing phpunit\/php-code-coverage (6.1.4): Loading from cache\r\n  - Installing doctrine\/instantiator (1.1.0): Loading from cache\r\n  - Installing symfony\/polyfill-ctype (v1.10.0): Loading from cache\r\n  - Installing webmozart\/assert (1.4.0): Loading from cache\r\n  - Installing phpdocumentor\/reflection-common (1.0.1): Loading from cache\r\n  - Installing phpdocumentor\/type-resolver (0.4.0): Loading from cache\r\n  - Installing phpdocumentor\/reflection-docblock (4.3.0): Loading from cache\r\n  - Installing phpspec\/prophecy (1.8.0): Loading from cache\r\n  - Installing phar-io\/version (2.0.1): Loading from cache\r\n  - Installing phar-io\/manifest (1.0.3): Loading from cache\r\n  - Installing myclabs\/deep-copy (1.8.1): Loading from cache\r\n  - Installing phpunit\/phpunit (7.5.6): Loading from cache\r\n  - Installing squizlabs\/php_codesniffer (2.9.2): Downloading (100%)         \r\n  - Installing zfcampus\/zf-composer-autoloading (2.1.0): Downloading (connectingDownloading (100%)         \r\n  - Installing zendframework\/zend-stratigility (3.1.0): Downloading (connecting.Downloading (100%)         \r\n  - Installing zendframework\/zend-diactoros (2.1.1):Downloading (100%)         )\r\n  - Installing zendframework\/zend-httphandlerrunner (1.1.0): Downloading (connecDownloading (100%)         \r\n    Installing Zend\\HttpHandlerRunner\\ConfigProvider from package zendframework\/zend-httphandlerrunner\r\n  - Installing zendframework\/zend-expressive (3.2.1): Downloading (connecting...Downloading (100%)         \r\n  - Installing zendframework\/zend-eventmanager (3.2.1): Downloading (connecting.Downloading (100%)         \r\n  - Installing zendframework\/zend-code (3.3.1): Loading from cache\r\n  - Installing symfony\/polyfill-mbstring (v1.10.0): Loading from cache\r\n  - Installing symfony\/contracts (v1.0.2): Loading from cache\r\n  - Installing symfony\/console (v4.2.4): Downloading (100%)         \r\n  - Installing psr\/log (1.1.0): Loading from cache\r\n  - Installing zendframework\/zend-expressive-tooling (1.2.0): Downloading (conneDownloading (100%)         \r\n  - Installing zfcampus\/zf-development-mode (3.2.0):Downloading (100%)         )\r\n  - Installing filp\/whoops (2.3.1): Downloading (100%)         \r\nzendframework\/zend-expressive-template suggests installing zendframework\/zend-expressive-twigrenderer (^2.0 to use the Twig template renderer)\r\nzendframework\/zend-expressive-template suggests installing zendframework\/zend-expressive-zendviewrenderer (^2.0 to use the zend-view PhpRenderer template renderer)\r\nzendframework\/zend-expressive-router suggests installing zendframework\/zend-expressive-aurarouter (^3.0 to use the Aura.Router routing adapter)\r\nzendframework\/zend-expressive-router suggests installing zendframework\/zend-expressive-zendrouter (^3.0 to use the zend-router routing adapter)\r\nzendframework\/zend-config-aggregator suggests installing zendframework\/zend-config (Allows loading configuration from XML, INI, YAML, and JSON files)\r\nzendframework\/zend-config-aggregator suggests installing zendframework\/zend-config-aggregator-modulemanager (Allows loading configuration from zend-mvc Module classes)\r\nzendframework\/zend-config-aggregator suggests installing zendframework\/zend-config-aggregator-parameters (Allows usage of templated parameters within your configuration)\r\nzendframework\/zend-servicemanager suggests installing ocramius\/proxy-manager (ProxyManager 1.* to handle lazy initialization of services)\r\nsebastian\/global-state suggests installing ext-uopz (*)\r\nphpunit\/phpunit suggests installing phpunit\/php-invoker (^2.0)\r\nzendframework\/zend-expressive suggests installing zendframework\/zend-auradi-config (^1.0 to use Aura.Di dependency injection container)\r\nzendframework\/zend-expressive suggests installing zendframework\/zend-pimple-config (^1.0 to use Pimple for dependency injection container)\r\nzendframework\/zend-code suggests installing doctrine\/annotations (Doctrine\\Common\\Annotations &gt;=1.0 for annotation features)\r\nsymfony\/contracts suggests installing psr\/cache (When using the Cache contracts)\r\nsymfony\/contracts suggests installing symfony\/cache-contracts-implementation\r\nsymfony\/contracts suggests installing symfony\/service-contracts-implementation\r\nsymfony\/contracts suggests installing symfony\/translation-contracts-implementation\r\nsymfony\/console suggests installing symfony\/event-dispatcher\r\nsymfony\/console suggests installing symfony\/lock\r\nsymfony\/console suggests installing symfony\/process\r\nfilp\/whoops suggests installing symfony\/var-dumper (Pretty print complex values better with var-dumper available)\r\nfilp\/whoops suggests installing whoops\/soap (Formats errors as SOAP responses)\r\nWriting lock file\r\nGenerating autoload files\r\nocramius\/package-versions:  Generating version class...\r\nocramius\/package-versions: ...done generating version class\r\n&gt; zf-development-mode enable\r\nYou are now in development mode.<\/pre>\n<p>Then go to the project root directory:<\/p>\n<pre class=\"lang:default decode:true \">teddy@teddy:~\/Documents\/works$ cd zend-expressive-skeleton\/<\/pre>\n<p>Run the project<\/p>\n<pre class=\"lang:default decode:true \">teddy@teddy:~\/Documents\/works\/zend-expressive-skeleton$ composer run --timeout=0 serve<\/pre>\n<p>Then open it on your browser: http:\/\/localhost:8080\/<br \/>\nNOTE: Make sure no other service running port 8080. If it exist, please stop it. In my composer nginx running port 8080. So I need to stop nginx (sudo service nginx stop).<\/p>\n<p>Create Login<br \/>\nI need to install a few components:<\/p>\n<pre class=\"lang:default decode:true \">teddy@teddy:~\/Documents\/works\/zend-expressive-skeleton$ composer require \\\r\n&gt;      zendframework\/zend-form:^2.11 \\\r\n&gt;      zendframework\/zend-i18n:^2.7 \\\r\n&gt;      zendframework\/zend-expressive-authentication:^1.0 \\\r\n&gt;      zendframework\/zend-expressive-authentication-session:^1.0 \\\r\n&gt;      zendframework\/zend-expressive-session:^1.0 \\\r\n&gt;      zendframework\/zend-expressive-session-ext:^1.0\r\n.\/composer.json has been updated\r\nLoading composer repositories with package information\r\nUpdating dependencies (including require-dev)\r\nPackage operations: 11 installs, 0 updates, 0 removals\r\n  - Installing zendframework\/zend-expressive-session (1.2.1): Downloading (conneDownloading (100%)         \r\n\r\n  Please select which config file you wish to inject 'Zend\\Expressive\\Session\\ConfigProvider' into:\r\n  [0] Do not inject\r\n  [1] config\/config.php\r\n  Make your selection (default is 1):\r\n\r\n  Remember this option for other packages of the same type? (Y\/n)Y\r\n    Installing Zend\\Expressive\\Session\\ConfigProvider from package zendframework\/zend-expressive-session\r\n  - Installing zendframework\/zend-expressive-authentication (1.1.0): DownloadingDownloading (100%)         \r\n    Installing Zend\\Expressive\\Authentication\\ConfigProvider from package zendframework\/zend-expressive-authentication\r\n  - Installing zendframework\/zend-expressive-authentication-session (1.0.0): DowDownloading (100%)         \r\n    Installing Zend\\Expressive\\Authentication\\Session\\ConfigProvider from package zendframework\/zend-expressive-authentication-session\r\n  - Installing dflydev\/fig-cookies (v2.0.0): Downloading (100%)         \r\n  - Installing zendframework\/zend-expressive-session-ext (1.6.0): Downloading (cDownloading (100%)         \r\n    Installing Zend\\Expressive\\Session\\Ext\\ConfigProvider from package zendframework\/zend-expressive-session-ext\r\n  - Installing zendframework\/zend-hydrator (3.0.1): Downloading (100%)         \r\n    Installing Zend\\Hydrator\\ConfigProvider from package zendframework\/zend-hydrator\r\n  - Installing zendframework\/zend-validator (2.12.0): Downloading (connecting...Downloading (100%)         \r\n    Installing Zend\\Validator\\ConfigProvider from package zendframework\/zend-validator\r\n  - Installing zendframework\/zend-filter (2.9.1): Loading from cache\r\n    Installing Zend\\Filter\\ConfigProvider from package zendframework\/zend-filter\r\n  - Installing zendframework\/zend-inputfilter (2.10.0): Loading from cache\r\n    Installing Zend\\InputFilter\\ConfigProvider from package zendframework\/zend-inputfilter\r\n  - Installing zendframework\/zend-form (2.14.1): Downloading (100%)         \r\n    Installing Zend\\Form\\ConfigProvider from package zendframework\/zend-form\r\n  - Installing zendframework\/zend-i18n (2.9.0): Loading from cache\r\n    Installing Zend\\I18n\\ConfigProvider from package zendframework\/zend-i18n\r\nzendframework\/zend-expressive-session suggests installing zendframework\/zend-expressive-csrf (^1.0 || ^1.0-dev for CSRF protection capabilities)\r\nzendframework\/zend-expressive-session suggests installing zendframework\/zend-expressive-flash (^1.0 || ^1.0-dev for flash message capabilities)\r\nzendframework\/zend-expressive-authentication suggests installing zendframework\/zend-expressive-authentication-basic (Provides an HTTP Basic Authentication AuthenticationInterface implementation)\r\nzendframework\/zend-expressive-authentication suggests installing zendframework\/zend-expressive-authentication-zendauthentication (Provides a zend-authentication AuthenticationInterface implementation)\r\nzendframework\/zend-hydrator suggests installing zendframework\/zend-serializer (^2.9, to use the SerializableStrategy)\r\nzendframework\/zend-validator suggests installing zendframework\/zend-db (Zend\\Db component, required by the (No)RecordExists validator)\r\nzendframework\/zend-validator suggests installing zendframework\/zend-math (Zend\\Math component, required by the Csrf validator)\r\nzendframework\/zend-validator suggests installing zendframework\/zend-i18n-resources (Translations of validator messages)\r\nzendframework\/zend-validator suggests installing zendframework\/zend-session (Zend\\Session component, ^2.8; required by the Csrf validator)\r\nzendframework\/zend-validator suggests installing zendframework\/zend-uri (Zend\\Uri component, required by the Uri and Sitemap\\Loc validators)\r\nzendframework\/zend-filter suggests installing zendframework\/zend-crypt (Zend\\Crypt component, for encryption filters)\r\nzendframework\/zend-filter suggests installing zendframework\/zend-uri (Zend\\Uri component, for the UriNormalize filter)\r\nzendframework\/zend-form suggests installing zendframework\/zend-captcha (^2.7.1, required for using CAPTCHA form elements)\r\nzendframework\/zend-form suggests installing zendframework\/zend-view (^2.6.2, required for using the zend-form view helpers)\r\nzendframework\/zend-form suggests installing zendframework\/zendservice-recaptcha (in order to use the ReCaptcha form element)\r\nzendframework\/zend-i18n suggests installing zendframework\/zend-cache (Zend\\Cache component)\r\nzendframework\/zend-i18n suggests installing zendframework\/zend-config (Zend\\Config component)\r\nzendframework\/zend-i18n suggests installing zendframework\/zend-i18n-resources (Translation resources)\r\nzendframework\/zend-i18n suggests installing zendframework\/zend-view (You should install this package to use the provided view helpers)\r\nWriting lock file\r\nGenerating autoload files\r\nocramius\/package-versions:  Generating version class...\r\nocramius\/package-versions: ...done generating version class<\/pre>\n<p>Ok. I want to put the authentication if any visitor want to visit the homepage so he\/she need to login first. I need to create a route for this. so modify config\/routes.php file like this:<\/p>\n<pre class=\"lang:default decode:true \">...\r\nreturn function (Application $app, MiddlewareFactory $factory, ContainerInterface $container) : void {\r\n    \/\/$app-&gt;get('\/', App\\Handler\\HomePageHandler::class, 'home');\r\n    $app-&gt;route('\/', [\r\n        \\Zend\\Expressive\\Authentication\\AuthenticationMiddleware::class,\r\n        App\\Handler\\HomePageHandler::class,\r\n    ], ['GET'], 'home');\r\n    ...\r\n};<\/pre>\n<p>comment the default home route then add a new route like above. If we refresh our browser for the homepage, it&#8217;d show this error:<\/p>\n<pre class=\"lang:default decode:true \">Service with name \"Zend\\Expressive\\Authentication\\AuthenticationMiddleware\" could not be created. Reason: AuthenticationInterface service is missing<\/pre>\n<p>we need to register &#8216;Zend\\Expressive\\Authentication\\AuthenticationInterface&#8217; under &#8216;factories&#8217; config in config\/autoload\/dependencies.global.php.:<\/p>\n<pre class=\"lang:default decode:true\">return [\r\n    ..\r\n    'dependencies' =&gt; [\r\n        ...\r\n        \/\/ Use 'factories' for services provided by callbacks\/factory classes.\r\n        'factories'  =&gt; [\r\n            \/\/ Fully\\Qualified\\ClassName::class =&gt; Fully\\Qualified\\FactoryName::class,\r\n            Zend\\Expressive\\Authentication\\AuthenticationInterface::class =&gt; Zend\\Expressive\\Authentication\\Session\\PhpSessionFactory::class\r\n        ],\r\n    ],\r\n];<\/pre>\n<p>If we refresh our browser again, it&#8217;d show another error:<\/p>\n<pre class=\"lang:default decode:true\">Service with name \"Zend\\Expressive\\Authentication\\AuthenticationInterface\" could not be created. Reason: UserRepositoryInterface service is missing for authentication<\/pre>\n<p>So I modify again config\/autoload\/dependencies.global.php to add &#8216;Zend\\Expressive\\Authentication\\UserRepositoryInterface&#8217; class in &#8216;aliases&#8217; config:<\/p>\n<pre class=\"lang:default decode:true \">return [\r\n   ...\r\n    'dependencies' =&gt; [\r\n        ...\r\n        'aliases' =&gt; [\r\n            \/\/ Fully\\Qualified\\ClassOrInterfaceName::class =&gt; Fully\\Qualified\\ClassName::class,\r\n            Zend\\Expressive\\Authentication\\UserRepositoryInterface::class =&gt; Zend\\Expressive\\Authentication\\UserRepository\\PdoDatabase::class\r\n        ],\r\n       ...\r\n    ],\r\n];\r\n<\/pre>\n<p>When I refresh the browser again. This error would be appear:<\/p>\n<pre class=\"lang:default decode:true\">Service with name \"Zend\\Expressive\\Authentication\\AuthenticationInterface\" could not be created. Reason: The redirect configuration is missing for authentication<\/pre>\n<p>So I need to put my database credentials to connect zend expressive to mysql database in config\/autoload\/local.php file (if this file not exist, please create one):<\/p>\n<pre class=\"lang:default decode:true \">return [\r\n    'authentication' =&gt; [\r\n        'pdo' =&gt; [\r\n            'dsn'   =&gt; 'mysql:host=localhost;dbname=expressive',\r\n            'username' =&gt; 'your-mysql-username',\r\n            'password' =&gt; ''your-mysql-password',\r\n            'table' =&gt; 'users',\r\n            'field' =&gt; [\r\n                'identity' =&gt; 'username',\r\n                'password' =&gt; 'password',\r\n            ],\r\n        ],\r\n        'redirect' =&gt; '\/login',\r\n    ],\r\n];<\/pre>\n<p>Please create a new database &#8216;expressive&#8217; and a new table &#8216;users&#8217; first. The users table consist of only two fields now. There are username (varchar 100) and password (varchar 100). I put &#8216;redirect&#8217; value to &#8216;\/login&#8217; so it&#8217;d redirect the homepage to login page. Make sure the credentials is correct. If not you&#8217;d get an error like this:<\/p>\n<pre class=\"lang:default decode:true \">Service with name \"Zend\\Expressive\\Authentication\\UserRepository\\PdoDatabase\" could not be created. Reason: SQLSTATE[HY000] [1045] Access denied for user ''@'localhost' (using password: NO)<\/pre>\n<p>Then I refresh my browser again. Another error is coming up:<\/p>\n<pre class=\"lang:default decode:true \">Request is missing the attribute Zend\\Expressive\\Session\\SessionMiddleware::SESSION_ATTRIBUTE (\"session\"); perhaps you forgot to inject the Zend\\Expressive\\Session\\SessionMiddleware prior to the Zend\\Expressive\\Authentication\\AuthenticationMiddleware?<\/pre>\n<p>Here we need &#8216;Zend\\Expressive\\Session\\SessionMiddleware&#8217; class before routing middleware. So add it in config\/pipeline.php:<\/p>\n<pre class=\"lang:default decode:true \">return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container) : void {\r\n    ...\r\n\r\n    $app-&gt;pipe(\\Zend\\Expressive\\Session\\SessionMiddleware::class);\r\n\r\n    \/\/ Register the routing middleware in the middleware pipeline.\r\n    \/\/ This middleware registers the Zend\\Expressive\\Router\\RouteResult request attribute.\r\n    $app-&gt;pipe(RouteMiddleware::class);\r\n\r\n    ...\r\n};<\/pre>\n<p>We fixed those errors until here. When we refresh our browser, we&#8217;d get the login page. But the content is showing 404 because we haven&#8217;t defined the login page!<a href=\"http:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2019\/03\/login_404.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3730\" src=\"http:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2019\/03\/login_404-1024x367.jpg\" alt=\"\" width=\"840\" height=\"301\" srcset=\"https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2019\/03\/login_404-1024x367.jpg 1024w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2019\/03\/login_404-300x108.jpg 300w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2019\/03\/login_404-768x275.jpg 768w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2019\/03\/login_404.jpg 1038w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/a>Create the login form. Add a new file &#8216;LoginForm.php&#8217; in &#8216;src\/App\/Form&#8217; directory. The login form will show username and password fields. The post the form, I&#8217;ll put a submit button:<\/p>\n<pre class=\"lang:default decode:true \">&lt;?php\r\ndeclare(strict_types=1);\r\nnamespace App\\Form;\r\n\r\nuse Zend\\Form\\Form;\r\nuse Zend\\InputFilter\\InputFilterProviderInterface;\r\nuse Zend\\Form\\Element\\Text;\r\nuse Zend\\Form\\Element\\Password;\r\n\r\nclass LoginForm extends Form implements InputFilterProviderInterface\r\n{\r\n    public function __construct()\r\n    {\r\n        parent::__construct('login-form');\r\n    }\r\n\r\n    public function init()\r\n    {\r\n        $this-&gt;add([\r\n            'type' =&gt; Text::class,\r\n            'name' =&gt; 'username',\r\n            'options' =&gt; [\r\n                'label' =&gt; 'Username',\r\n            ],\r\n        ]);\r\n \r\n        $this-&gt;add([\r\n            'type' =&gt; Password::class,\r\n            'name' =&gt; 'password',\r\n            'options' =&gt; [\r\n                'label' =&gt; 'Password',\r\n            ],\r\n        ]);\r\n \r\n        $this-&gt;add([\r\n            'name' =&gt; 'Login',\r\n            'type' =&gt; 'submit',\r\n            'attributes' =&gt; [\r\n                'value' =&gt; 'Login',\r\n            ],\r\n        ]);\r\n    }\r\n\r\n    public function getInputFilterSpecification()\r\n    {\r\n        return [\r\n            [\r\n                'name' =&gt; 'username',\r\n                'required' =&gt; true,\r\n                'filters' =&gt; [\r\n                    ['name' =&gt; 'StripTags'],\r\n                    ['name' =&gt; 'StringTrim'],\r\n                  ],\r\n            ],\r\n \r\n            [\r\n                'name' =&gt; 'password',\r\n                'required' =&gt; true,\r\n                'filters' =&gt; [\r\n                    ['name' =&gt; 'StripTags'],\r\n                    ['name' =&gt; 'StringTrim'],\r\n                ],\r\n            ],\r\n        ];\r\n    }\r\n}\r\n<\/pre>\n<p>then create a login page handler with inject it with login form with the following factory in src\/App\/Handler\/LoginPageFactory.php:<\/p>\n<pre class=\"lang:default decode:true \">&lt;?php\r\ndeclare(strict_types=1);\r\n\r\nnamespace App\\Handler;\r\n\r\nuse Psr\\Container\\ContainerInterface;\r\nuse Psr\\Http\\Server\\MiddlewareInterface;\r\nuse Zend\\Expressive\\Template\\TemplateRendererInterface;\r\nuse Zend\\Form\\FormElementManager;\r\nuse App\\Form\\LoginForm;\r\n\r\nclass LoginPageFactory\r\n{\r\n    public function __invoke(ContainerInterface $container) : MiddlewareInterface\r\n    {\r\n        $template = $container-&gt;get(TemplateRendererInterface::class);\r\n        $loginForm = $container-&gt;get(FormElementManager::class)-&gt;get(LoginForm::class);\r\n\r\n        return new LoginPageHandler($template, $loginForm);\r\n    }\r\n}\r\n<\/pre>\n<p>The LoginPageHandler itself can be initialized in src\/App\/Handler\/LoginPageHandler.php:<\/p>\n<pre class=\"lang:default decode:true \">&lt;?php\r\ndeclare(strict_types=1);\r\n\r\nnamespace App\\Handler;\r\n\r\nuse Psr\\Http\\Server\\MiddlewareInterface;\r\nuse Zend\\Expressive\\Template\\TemplateRendererInterface;\r\nuse App\\Form\\LoginForm;\r\nuse Psr\\Http\\Message\\ServerRequestInterface;\r\nuse Psr\\Http\\Server\\RequestHandlerInterface;\r\nuse Psr\\Http\\Message\\ResponseInterface;\r\nuse Zend\\Expressive\\Session\\SessionMiddleware;\r\nuse Zend\\Expressive\\Authentication\\UserInterface;\r\nuse Zend\\Diactoros\\Response\\RedirectResponse;\r\nuse Zend\\Diactoros\\Response\\HtmlResponse;\r\n\r\nclass LoginPageHandler implements MiddlewareInterface\r\n{\r\n    private $template;\r\n    private $loginForm;\r\n\r\n    public function __construct(\r\n        TemplateRendererInterface   $template,\r\n        LoginForm                   $loginForm\r\n    )\r\n    {\r\n        $this-&gt;template = $template;\r\n        $this-&gt;loginForm = $loginForm;\r\n    }\r\n\r\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\r\n    {\r\n        $session = $request-&gt;getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);\r\n        if ($session-&gt;has(UserInterface::class)) {\r\n            return new RedirectResponse('\/');\r\n        }\r\n\r\n        $error = '';\r\n\r\n        return new HtmlResponse(\r\n            $this-&gt;template-&gt;render('app::login-page', [\r\n                'form' =&gt; $this-&gt;loginForm,\r\n                'error' =&gt; $error,\r\n            ])\r\n        );\r\n    }\r\n}\r\n<\/pre>\n<p>Above, we redirect to &#8216;\/&#8217; page when there is a session data as it already authenticated check. We are going to add authentication process next.<\/p>\n<p>The Login form can be as simple as the following in templates\/app\/login-page.phtml<\/p>\n<pre class=\"lang:default decode:true \">&lt;?php\r\n\r\necho $error;\r\n\r\n$form-&gt;prepare();\r\n\r\necho $this-&gt;form($form);<\/pre>\n<p>We can register the LoginPageHandler at App\\ConfigProvider::getDependencies() config in src\/App\/ConfigProvider.php<\/p>\n<pre class=\"lang:default decode:true\">...\r\nclass ConfigProvider\r\n{\r\n    ...\r\n\r\n    \/**\r\n     * Returns the container dependencies\r\n     *\/\r\n    public function getDependencies() : array\r\n    {\r\n        return [\r\n            'invokables' =&gt; [\r\n                ...\r\n            ],\r\n            'factories'  =&gt; [\r\n                Handler\\HomePageHandler::class =&gt; Handler\\HomePageHandlerFactory::class,\r\n                Handler\\LoginPageHandler::class =&gt; Handler\\LoginPageFactory::class,\r\n            ],\r\n        ];\r\n    }\r\n\r\n    ...\r\n}\r\n<\/pre>\n<p>The routing can be registered as follows with add \\Zend\\Expressive\\Authentication\\AuthenticationMiddleware::class for next middleware in config\/routes.php:<\/p>\n<pre class=\"lang:default decode:true \">return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container) : void {\r\n    ...\r\n\r\n    $app-&gt;route('\/login', [\r\n        App\\Handler\\LoginPageHandler::class,\r\n        \\Zend\\Expressive\\Authentication\\AuthenticationMiddleware::class,\r\n    ], ['GET', 'POST'], 'login');\r\n    \r\n    ...\r\n};<\/pre>\n<p>Until this, when I refresh the browser, I got this error and can&#8217;t continue anymore. I still dont know why the error is happened:<\/p>\n<pre class=\"lang:default decode:true \">Too few arguments to function App\\Handler\\LoginPageHandler::__construct(), 0 passed in \/home\/teddy\/Documents\/works\/zend-expressive-skeleton\/vendor\/zendframework\/zend-expressive\/src\/MiddlewareContainer.php on line 64 and exactly 2 expected<\/pre>\n<p>I need learn Zend Expressive more!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ref: https:\/\/docs.zendframework.com\/zend-expressive\/ https:\/\/docs.zendframework.com\/zend-expressive\/v3\/getting-started\/quick-start\/ Create Login functionality in Expressive&nbsp;3 Install via composer: teddy@teddy:~\/Documents\/works$ composer create-project zendframework\/zend-expressive-skeleton Installing zendframework\/zend-expressive-skeleton (3.2.3) &#8211; Installing zendframework\/zend-expressive-skeleton (3.2.3): Downloading (connDownloading (100%) Created project in \/home\/teddy\/Documents\/works\/zend-expressive\/zend-expressive-skeleton &gt; ExpressiveInstaller\\OptionalPackages::install Setting up optional packages Setup data and cache dir Removing installer development dependencies What type of installation would you like? [1] Minimal (no default &hellip; <a href=\"https:\/\/myprojects.advchaweb.com\/index.php\/2019\/03\/12\/zend-framework-3-zend-expressive\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Zend Framework 3: Zend Expressive&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48,13,84],"tags":[],"class_list":["post-3722","post","type-post","status-publish","format-standard","hentry","category-php-2","category-tutorial","category-zend-framework"],"_links":{"self":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts\/3722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/comments?post=3722"}],"version-history":[{"count":10,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts\/3722\/revisions"}],"predecessor-version":[{"id":3733,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts\/3722\/revisions\/3733"}],"wp:attachment":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/media?parent=3722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/categories?post=3722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/tags?post=3722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}