Existing codebase is 10 years old
High maintenance cost
Started with no unit tests - singletons everywhere
Layers and roles not properly defined / documented - interdependencies
OOP before php had
Private/protected/static
Closures
Namespaces
Late static binding
And much more
Not built for an AJAX and REST world
5/17/2013gg@ez.no Slide 6
Why change?
Everyone loves NEW!
Existing codebase is 10 years old
Widely deployed
Well debugged
Pitfalls have mostly been uncovered by now
Proven to scale
Well known:
Documentation improved over years
Tutorials, forums, blogs, aggregators
Active community of practitioners
Official training courses
5/17/2013gg@ez.no Slide 7
Why change?
Do not forget drawbacks
Focus on our core business
Experience Management
Content Management
NOT Framework maintenance
Durable Architecture
API stability
Battle tested / not (only) the latest trend
Scalability
Lively Community!
5/17/2013gg@ez.no Slide 8
Picking a framework for a platform rebuild
• Simple Integration with existing API
• HMVC (Hierarchical Model View Controller) stack
• Decoupled Components
• Dependency Injection
• Good Template Engine
• Extensible, Open, Reliable ;-)
5/17/2013gg@ez.no Slide 9
Prerequisites
Product Management SCRUM Story:
«As an existing user, I don’t want to be pissed off by a new
#@!$% version!»
5/17/2013gg@ez.no Slide 15
Backwards compatibility
(life sucks)
Product Management SCRUM Story:
«As an existing user, I don’t want to be pissed off by a new
#@!$% version!»
• 100% Data Compatible (same DB scheme)
• Possibility to include legacy templates in the new ones
• Routing fallback
• Load legacy content templates with legacy rules
• Settings
• Access Symfony services from legacy modules
5/17/2013gg@ez.no Slide 16
Backwards compatibility: the objectives
Product Management SCRUM Story:
«As an existing user, I don’t want to be pissed off by a new
#@!$% version!»
• 100% Data Compatible (same DB scheme)
• Possibility to include legacy templates in the new ones
• Routing fallback
• Load legacy content templates with legacy rules
• Settings
• Access Symfony services from legacy modules
5/17/2013gg@ez.no Slide 17
Backwards compatibility: the objectives
Product Management SCRUM Story:
«As an existing user, I don’t want to be pissed off by a new
#@!$% version!»
• 100% Data Compatible (same DB scheme)
• Possibility to include legacy templates in the new ones
• Routing fallback
• Load legacy content templates with legacy rules
• Settings
• Access Symfony services from legacy modules
Challenge Accepted
5/17/2013gg@ez.no Slide 19
BC: the challenge
New Core: a standard Simfony app
Legacy stack isolated in a dedicated
directory
5/17/2013gg@ez.no Slide 23
Refactoring: directory layout
use SymfonyComponentHttpFoundationRequest;
require_once __DIR__ . '/../ezpublish/autoload.php'; // set up class autoloading
require_once __DIR__ . '/../ezpublish/EzPublishKernel.php';
$kernel = new EzPublishKernel( 'dev', true ); // extends the Sf Kernel class
$kernel->loadClassCache(); // a method from parent class
$request = Request::createFromGlobals();
$response = $kernel->handle( $request );
$response->send();
$kernel->terminate( $request, $response );
The Kernel class wraps the HTTPKernel
It adds a Service Container
It allows to register bundles via registerBundles()
5/17/2013gg@ez.no Slide 24
The new frontend controller
Using Symfony HTTP Kernel
Sandbox legacy code in a closure
Index.php had to be refactored (from 1100 lines to 20)
Logic moved to a php class
Separated environment setup from execution and teardown
runCallback() sets up the global legacy environment
5/17/2013gg@ez.no Slide 25
Refactoring: bridging Legacy code
The ChainRouter from the Sf CMF project is used
5/17/2013gg@ez.no Slide 26
Routing: seamless integration
eZ4 had an incomplete REST API
Only functionality available: reading content
Based on Zeta Components MVC component
A new API has been implemented
Full reading and writing of content is possible
All “dictionary” data is also available
Content-type for response can be JSON or XML (with an XSD!)
Fully restful
Usage of all HTTP verbs (and then some: PATCH)
Respect http headers of request (eg: “Accept”)
HATEOAS: use urls as resource ids
No separate request handling framework needed: pure Symfony routing
Bonus points: a client for the REST API, implements the same interfaces exposed
by the local PHP API – network transparency!!!
5/17/2013gg@ez.no Slide 27
REST API