Migration from 2.1 to 3.0

1. Introduction

Version 3.0 of the Adventure PHP Framework contains an all-new parser. Based on this new component various new features and optimizations have been introduced.

As of the 3.0 release enhancement of version version 2.1 will be discontinued. Security and bug fixes will be available until end of 2015.

This article shows how to update your application to APF version 3.0. As you might already be familiar with from previous versions migration can be done in an automated fashion for nearly all changes. For this reason, the release contains two scripts: migrate-code.sh to update your HTML and PHP files and migrate-config.sh for configuration files.

The APF team recommends to use the migration scripts rather than upgrading manually. This not only saves time and money but also ensure that all relevant areas of your project code are covered.

The below chapters contain an in-depth description on how to switch to APF 3.0 and which kind of changes have to be applied to your existing application(s) to run them based on this version.

2. Automated migration

As you might already be familiar with from release 2.1 migration can be done using the migration script shipped along with the release. This release includes changes to code, templates, and configuration files. Using migrate-code.sh and migrate-config.sh you can easily be adapted your existing application to the new scheme.

Please be sure to execute all steps described under Migration from 2.0 to 2.1. In case you are using an order version of the APF, please completely migrate to version 2.1. Instructions can be taken from Articles.
Please create a backup before execution of the scripts to be able to restore parts of your application if necessary!

In case your development environment is windows, please install the latest cygwin version (download under cygwin.com). Migration for Windows Batch Scripts is not supported.

To update the code files to the latest scheme, please execute the script as follows:

Please change to the code directory before execution to avoid unexpected results.
Code
$ /path/to/APF/migration/migrate-code.sh /cygdrive/c/xampp/php/php ############################################# # APF 3.0 automatic code migration # ############################################# Checking PHP executable available ... [OK] Using given php executable at /cygdrive/c/xampp/php/php. PHP Version: 5.4.16. ############################################# Starting migration ... * Migrate taglib declaration statements ... * Consolidate tag usage ... * Remove redundant tag lib registration ... * Switch to new place holder logic ... ############################################# Migration done! Please check your code and follow instructions within migration documentation!

To update the configuration files to the latest scheme, please execute the script as follows:

Please change to the configuration directory before execution to avoid unexpected results.
Code
$ /path/to/APF/migration/migrate-config.sh /cygdrive/c/xampp/php/php ############################################# # APF 3.0 automatic configuration migration # ############################################# Checking PHP executable available ... [OK] Using given php executable at /cygdrive/c/xampp/php/php. PHP Version: 5.4.16. ############################################# Starting configuration migration ... * Migrate cache configuration ... * Migrate pager configuration ... ############################################# Migration done! Please check your configuration and follow instructions within migration documentation!

3. Manual steps

Unfortunately, not all components of your application can be migrated by the delivered scripts. This chapter lists all changes to be applied by hand.

3.1. Front controller

With issue ID#207 an old class design weakness has been removed from the code base. Class APFObject now is no longer responsible for storing XML attributes. This has been moved to Document as this class represents an APF DOM node.

With this change, FrontControllerInput had to be adapted as well to save the action parameters in a different way: $this->parameters.

In order to update to this new version please replace all occurrences of the following symbols within classes derived from FrontControllerInput as follows:

Old name New Name
(APFObject) $this->attributes (FrontControllerInput) $this->parameters
FrontControllerInput::getAttribute() FrontControllerInput::getParameter()
FrontControllerInput::getAttributes() FrontControllerInput::getParameters()
FrontControllerInput::setAttribute() FrontControllerInput::setParameter()
FrontControllerInput::setAttributes() FrontControllerInput::setParameters()
FrontControllerInput::deleteAttribute() (no longer supported)
FrontControllerInput::addAttribute() (no longer supported)

3.2. APFObject

As mentioned in chapter 3.1 the attribute handling has been removed from APFObject. This change also effects classes derived from APFObject that are being used as view models and rely in the $this->attributes field.

Please adapt all use cases to run your application in APF 3.0.

3.3. Place holder

The functionality to define simple place holders within a <html:placeholder /> tag has been removed in release 3.0.

In case you are using code like

APF template
<html:placeholder name="foo">This is a {bar} thing.</html:placeholder>

please rewrite it to:

APF template
This is a ${bar} thing.

Within controllers usage of the place holders changes from

PHP code
$this->setStringPlaceHolder('foo', 'bar', '...');

to

PHP code
$this->setPlaceHolder('bar', '...');

3.4. Signature changeDateSelectorTag and TimeSelectorTag

Implementing ID#208 the signature of DateSelectorTag::getDate() and DateSelectorTag::setDate() as well as TimeSelectorTag::getTime() and TimeSelectorTag::setTime() have been adapted.

Both setters now take a string as well as an instance of DateTime initializing the tag. This allows better typing of data within your application.

The APF team recommends to start using DateTime to represent date and time valued with APF 3.0. This not only eases usage of both tags but also allows strong encapsulation of date and time values.

Both getter methods return a DateTime instance. This change requires changes to your code base (in contrast to the setters). In case you are using the following code to read and process the content of a DateSelectorTag like

PHP code
$date = &$form->getFormElementByName('date-of-birth'); $sql = 'INSERT INTO ... SET ..., dob = `' . $date->getDate() . '`, ... ';

please rewrite it to:

PHP code
$date = &$form->getFormElementByName('date-of-birth'); $sql = 'INSERT INTO ... SET ..., dob = `' . $date->getDate()->format('Y-m-d') . '`, ... ';

3.5. New request implementation

With implementation of ID#234 classes RequestHandler and HeaderManager have been replaced by an object-oriented Request and Response implementation as an abstraction of the HTTP communication.

This eases implementation and offers simple and easy-to-use methods for common tasks such as reading request content, manipulating HTTP responses, or redirecting to other URLs.

Switching to the new model is automated as much as possible by the automated migration but some parts need to be adapted by hand.

The following chapters describe the necessary adaptions to use the new Request and Response implementation.

Details on the request processing process of APF 3.0 can be found in chapter Request processing.

3.5.1. RequestHandler

In APF up to version 2.1 RequestHandler provided an abstraction for accessing content of the current request. All functionality is now contained in RequestImpl.

Updating using the migration scripts covers almost all use cases. The only exception is getValues() as this cannot be migrated due to complexity reasons. For this reason, please rewrite all use cases from e.g.

PHP code
$values = RequestHandler::getValues(array('page', 'sort' => 'asc'));

to

PHP code
$page = self::getRequest()->getParameter('page'); $sort = self::getRequest()->getParameter('sort', 'asc');

Alternatively, you may want to use the following code snippet to decrease impact on your code base:

PHP code
$values = array(); $request = self::getRequest(); foreach (array('page', 'sort' => 'asc') as $name => $default) { if (is_integer($name)) { $values[$default] = $request->getParameter($default); } else { $values[$name] = $request->getParameter($name, $default); } }

3.5.2. HeaderManager

In APF up to version 2.1 HeaderManager provided an interface to manipulate HTTP responses or to redirect users to certain URLs. All functionality contained there has been moved to ResponseImpl.

Migration of the HeaderManager can be done in an automated fashion for a great majority of use cases. The only exception is front controller actions as they heavily manipulate the response in most cases. For this reason, please review all actions within your project thoroughly.

The automated migration rewrite code blocks such as

PHP code
HeaderManager::send('Content-Type: application/json'); echo json_encode(array( 'headline' => $news->getHeadline(), 'subheadline' => $news->getSubHeadline(), 'content' => $news->getContent(), 'newscount' => $news->getNewsCount() )); exit(0);

to

PHP code
self::getResponse()->setHeader(new HeaderImpl('Content-Type', 'application/json')); echo json_encode(array( 'headline' => $news->getHeadline(), 'subheadline' => $news->getSubHeadline(), 'content' => $news->getContent(), 'newscount' => $news->getNewsCount() )); exit(0);

This leads to the fact that the Content-Type header is not sent to the browser as the ResponseImpl instance is not sent back. For this reason please change the code to:

PHP code
$response = self::getResponse(); $response->setHeader(new HeaderImpl('Content-Type', 'application/json')); $response->setBody(json_encode(array( 'headline' => $news->getHeadline(), 'subheadline' => $news->getSubHeadline(), 'content' => $news->getContent(), 'newscount' => $news->getNewsCount() ))); $response->send();

3.6. Interface change configuration

With implementation of ID#224 interface Configuration has been changed such that the getSection() method returns a Configuration instance in any case. This helps to avoid Null Pointer Exceptions in a very effective way and thus make application operation safer.

Along with the change method hasSection() has been introduced to check whether a configuration section really exists.

In order to operate your application accurately with version 3.0 adaption is required - especially for checks on configurations to exist. In case you are using code snippets like

PHP code
if ($config->getSection($this->getLanguage()) !== null) { ... } else { ... }

within your application please rewrite to comply with the following:

PHP code
if ($config->hasSection($this->getLanguage())) { ... } else { ... }

3.7. ServiceManager API

APF 3.0 introduces the constructor injection concept for Creation of objects and Services. This eases creation and instant initialization of objects and allows to declare dependencies within the constructor directly.

APFObject::getServiceObject() are already covered by the automated migration but ServiceManager::getServiceObject() calls must be updated by hand. Please check your application of this method is used and update code blocks like

PHP code
$model = & ServiceManager::getServiceObject( 'CMS\core\biz\CMSModel', $context, 'de', APFService::SERVICE_TYPE_SESSION_SINGLETON );

to

PHP code
$model = & ServiceManager::getServiceObject( 'CMS\core\biz\CMSModel', $context, 'de', [], APFService::SERVICE_TYPE_SESSION_SINGLETON );
Please note that deprecated methods APFObject::getAndInitServiceObject() and ServiceManager::getAndInitServiceObject() have been removed. Please use the capabilities described under Creation of objects and Services instead.

4. FAQ

The following chapters contain issues that came up during migration to the new version along with solutions:

4.1. Missing tag registration

Question

Calling the application it fails with:

Code
Fatal error: Uncaught exception 'APF\core\pagecontroller\ParserException' with message ' in ***/APF/core/pagecontroller/Document.php on line 1037 APF\core\pagecontroller\ParserException: No tag definition found for prefix "template" and name "placeholder" in document with type "APF\core\pagecontroller\TemplateTag"! Template code: [..]
Answer

This means that the migration script has not been executed on the current project or the tag is not yet registered for the current project. Please add an <core:addtaglib /> to your template or add a Document::addTagLib(...); to your index.php.

4.2. Old place holder format

Question

Calling the application it fails with:

Code
No closing tag found for tag <html:placeholder />! Template code: <html:placeholder name="anchor"> <a href="{URL}" title="{TITLE}" class="breadcrumb {CLASSES}" >{TEXT}</a></template:placeholder>
Antwort

Usage of string place holders is no longer supported by version 3.0. Please resolve all issues with the approach described in chapter 3.3. Above error message may be resolved as follows:

APF template
<a href="${URL}" title="${TITLE}" class="breadcrumb ${CLASSES}">${TEXT}</a>

Please note that the corresponding controller must be adapted as well.

5. Further optimisations

Tips for upgrading to version 3.0 and suggestions on how to optimize your application can be taken from article Updating from 2.1 to 3.0.

Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.
There are no comments belonging to this article.