Download the PHP package janatzend/zend-expressive-legacy-bridge without Composer
On this page you can find all versions of the php package janatzend/zend-expressive-legacy-bridge. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download janatzend/zend-expressive-legacy-bridge
More information about janatzend/zend-expressive-legacy-bridge
Files in janatzend/zend-expressive-legacy-bridge
Package zend-expressive-legacy-bridge
Short Description Package provides bridge functionality to run legacy apps inside Zend Expressive
License Apache-2.0
Informations about the package zend-expressive-legacy-bridge
Zend Expressive Legacy Bridge
Zend Expressive Legacy Bridge is a library which allows legacy apps based on Zend Framework 1 and Symfony 1 to be run as a middleware layer in Zend Expressive. The goal is to provide a REST API for these application without code changes of the original app.
Prerequisites
Zend Expressive Legacy Bridge requires PHP 7
Installation
To install with composer
Loading Legacy Bridge
Legacy Bridge is providing several services and middleware implementations. In order to load them in to the Zend Expressive application one has to insert the array provided by the ConfigProvider service into the section of the config container.
Example
If the the configuration is created according to the documentation here https://zendframework.github.io/zend-expressive/features/container/zend-servicemanager/#configuration-driven-container a file called should be placed in the directory with the following content:
This code is also used in the projects https://bitbucket.org/account/user/janatzendteam/projects/ELM and https://bitbucket.org/account/user/janatzendteam/projects/EX.
Usage
As there's probably no one-size-fits-all solution for the modernization problem, the Legacy Bridge is designed to provide a rich feature set usable in most cases, while allowing to modify all of the components so that they fit to the needs. That said, it's not a one-click or one-step solution, but an addition to the framework giving the option to extend the legacy functionality in a flexible way. The Legacy Bridge is responsible for providing a middleware implementation in which (nearly) the full execution flow of the ZF1 or Symfony 1 MVC application is encapsulated. However there's some manual work to do. In general one has to provide three different components:
Initialization
Initialization details of the legacy apps have to be customizable. For example the setting of the include path, the path to the configuration file, environment variables and more. The Legacy Bridge provides an option to define a service in which these details can be specified. In general it's more or less a copy and paste from the original index.php. See in the Examples section below how to implement.
Routing
An important question which has to be answered before utilizing the Legacy Bridge is: "How should the routing for the new REST API look like?" There are several options:
- prefix the path in the URL with something like or
- make use of the Accept-Header: if it is then a JSON response from the API should provided, otherwise the normal HTML output
- combination of both above
Example 1 shows how to use the Accept-Header, Example 2 is programmed to work with an prefix path
Hydrator
As the Legacy Bridge is not a screen scraper, the functionality of the bridge is taking care of disabling the rendering of the View component of the legacy app. Additionally redirects have to be catched/disabled. The View object is processed by a Hydrator or a Hydrator chain, which is responsible to output only the needed data in a structured format. Thanks to the hydrator, data can be filtered and especially objects that are passed to the view object in the legacy app can be resolved on a customized basis.
Examples
As there is not the one and only best practice for using the Legacy Bridge, for your convenience two examples have been provided, that are both using the same Legacy Bridge core but in a very different way and setup. Both examples have in common that the legacy app is running side-by-side to the new API functionality.
Zend Framework 1 application MyTracking
MyTracking is an Zend Framework 1 application which has been developed originally as a PoC in a customer engagement several years ago. MyTracking is a CRUD implementation for administrating (tracking) images in the database. Additionaly PDF's can be generated with the stored data.
MyTracking is also able to run on IBM i with DB2
Initialization
Zend Framework 1 applications need some information before the bootstrapping can be started. For example the include_path is normally set in the . But also environment variables like the information whether it's a production or a development system is done with constant at a very early stage. As this should not be done for the Expressive app, the Legacy Bridge allows to execute a callable at the very first step in the Bridge middleware. This callable must be found with the name in the config container. In this example a file defines the callable like this:
Routing
The of MyTracking is setting up the Zend Expressive application; the original has been renamed to .
ApiDecider
In order to provide an API the routes of the original app are not modified. Instead the value of the Accept-Header of the request decides whether the output should be HTML or JSON. The decision is made by the ApiDecider middleware which is placed between and :
That means that the ApiDecider is becoming active immediate after a successful routing. It checks for the Accept-Header value and if it equals to it calls the next middleware in the pipeline. Otherwise it is utilizing the LocationRedirector service and the pipeline execution is stopped. The LocationRedirector is rewriting the path from e.g. to and is redirecting to this location. The LocationRedirector expects a service called to which a request object is being passed. With its help the URL path can be rewritten. In this example this service is defined in a file :
API definition
The last definitions in , before actually running the application, are specifying the supported API / REST calls.
As one can notice, all of the routes are already available in the legacy app. This is necessary because the route is passed to the MVC and would not find a match if it was different to the original routes. However, with some additional functionality (see Example 2) one can also use a new route thanks to a custom route mapping mechanism.
Altough the definitions give the impression that is directly called for providing the middleware, this is not correct. Instead is an identifier for loading the . The reason for this can be found in the Legacy Bridge library code in file - the Legacy Bridge services are defined here. This mechanism gives the flexibility to overwrite the library core functionality very easy.
Hydrator
As the View is not rendered, custom Hydrators have to translate the View elements in a structure that can be output as JSON. The Zend_View object is holding all view variables as public instance vars. In the MyTracking example with the route the view object only contains one value, namely . Unfortunately the content of cannot be output without modifying, as it contains binary data (images are stored in DB) that should not appear in the JSON response. In order to provide a filter functionality, the file has been created. It contains a service that maps a route to a set of view items (in this example we only have one: ) and its corresponding Hydrator implementation:
The array key is reserved by the Legacy Bridge. is pointing to a Hydrator implementation, defined in the same file:
The interesting part here is not the actual code, as it is an implementation detail, but the fact that two so called Hydrator strategies are combined to a Hydrator chain; so the data in the value is transformed twice.
Symfony 1 application Jobeet
Jobeet is an application which has been developed in the context of a Symfony 1 online training tutorial.
See: http://symfony.com/legacy/doc/jobeet?orm=Doctrine
Initialization
The Jobeet application only needs a minimal effort to do the initialization, actually only the class file has to be included with the correct path. Therefore a file is containing the following code:
The Legacy Bridge executes the callable at the very first step of the Bridge middleware.
Routing
In this example the Zend Expressive Application setup is done in a file called . The original file was not touched. The new Jobeet API is dependent on a path prefix in the URL: . Therefore a rewrite rule was added in the file, which makes sure that is called when requesting the new path:
API definition
The last definitions in before actually running the application are specifying the supported API / REST calls.
Altough the definitions give the impression that is called directly called for providing the middleware, this is not correct. Instead is an identifier for loading the . The reason for this can be found in the Legacy Bridge library code in file - the Legacy Bridge services are defined here. This mechanism gives the flexibility to overwrite the library core functionality very easy.
Another thing which might confuse on a first sight is the fact that the original Jobeet app doesn't provide a functionality to display a list of all (job) categories. However, the first route from above does allow exactly this. Why is this possible? First, the start page of the Jobeet app, or better said the view object from the start page, contains information about the categories which are not displayed. In order to display this information we need a hydrator (see below), but also a mapping from to the start page route to load the correct action in the Bridge middleware. This mapping can be found in file :
The Legacy Bridge uses this config item to map a route from the API to the route of the legacy app that provides the necessary information.
Hydrator
As the View is not rendered, custom Hydrators have to translate the View elements in a structure that can be output as JSON. The view in Symfony 1 is holding all view variables in a varHolder container of an action view object. In the Jobeet example with the route resp. the view object contains a variable. This variable contains object arrays instead of scalar values in a structured format. Therefore a specific hydrator has to be defined in file for transforming the data into the needed format:
The array key is reserved by the Legacy Bridge. is pointing to a Hydrator definition in the same file:
The specified class is available in the folder. This class or the appropriate methods are working with the object arrays in order to filter the needed data.
All versions of zend-expressive-legacy-bridge with dependencies
zendframework/zend-expressive Version 1.0.0
zendframework/zend-expressive-router Version 1.2.0
zendframework/zend-hydrator Version 2.2.1
zendframework/zend-servicemanager Version 3.1.1
zendframework/zend-expressive-template Version 1.0.3
zendframework/zend-expressive-fastroute Version 1.2.0