Talk given by Lukasz Serwatka during the eZ Session Show, 6th episode, online. Learn more at http://www.meetup.com/eZ-Publish-Users-Developers/events/107927592/
Meet the eZ Publish Community on http://share.ez.no
2. 2013-04-23Presenter: Łukasz Serwatka Slide 2
Extending eZ Publish 5§
Presenter
Łukasz Serwatka
Product Management Technical Lead
lukasz.serwatka@ez.no
@lserwatka
§
Working with eZ since 1st of March 2005
§
Over 10 years of experience with eZ Publish
§
Former member of the Engineering team
§
eZ Publish & Polish PHP Community Member
§
Expert in mobile solutions (mobile applications & mobile strategies)
3. 13-4-26Presenter: Łukasz Serwatka Slide 3
Extending eZ Publish 5§
Preparation
§
Drivers for migration (challenges, requirements) - It is very important to
understand the drivers behind a migration effort
§
Inventory of current environment - Creating a detailed summary of the
current extension portfolio really helps in terms of understanding the scope
of a migration effort
§
Migration service provider - evaluate at least a couple of migration service
providers if you do not have migration skills and staff in-house.
§
Migration effort estimate - the estimate depends on many factors such as
extension size, database complexity, components, etc. Usually provided by
the migration service provider.
§
Training requirements - Training requirements for existing development
team on the new platform need to be assessed to ensure that they can
support the new environment effectively and can participate in the migration
process if required.
4. 13-4-26Presenter: Łukasz Serwatka Slide 4
Extending eZ Publish 5§
Preparation
§
Make in-depth analysis of the existing eZ Publish 4.x extension functionality
and code base, focusing especially on
§ External storage (custom tables)
§ Configuration (INI settings overrides)
§ CLI scripts
§ Template overrides
§ Datatypes
§ Edit handlers
§ Workflow events
§ AJAX calls
§ Translations
§ User interface (backend)
§
Carefully judge which elements can be natively implemented in eZ Publish 5
and which ones still require legacy kernel. Not all legacy features are
available in eZ Publish 5 yet, and it is an ongoing process to fill the gaps.
5. 13-4-26Presenter: Łukasz Serwatka Slide 5
Extending eZ Publish 5§
Preparation
§
The eZ Publish 5 supported extension points at the moment:
§ FieldTypes (with custom tables)
§ Templates (view providers for Content, Location and Blocks [since eZ Publish
5.1])
§ Services (Persistence API)
§ Controllers & Actions (Routes)
§ Events (PostSiteAccessMatchEvent, PreContentViewEvent,
APIContentExceptionEvent)
− eZ/Publish/Core/MVC/Legacy/LegacyEvents.php
−
eZ/Publish/Core/MVC/Symfony/MVCEvents.php
6. 13-4-26Presenter: Łukasz Serwatka Slide 6
Extending eZ Publish 5§
New concepts in eZ Publish 5.x
eZ Publish 4.x eZ Publish 5.x
Module Controller, extends
eZBundleEzPublishCoreBundleController
Action & View Action: the method on the Controller to
execute. View is a (Twig) template that
displays the result of the Action.
eZTemplate Twig, new template engine, new syntax
fetch() Render function, HMVC concept, a function
that enables embedding if other controller
calls
Extension Bundle in the eZ Publish 5 (Symfony2)
CLI eZ Publish 5 ezpublish/console
component for creating command line
interfaces
INI settings YAML, recommended configuration type in
eZ Publish 5
7. 13-4-26Presenter: Łukasz Serwatka Slide 7
Extending eZ Publish 5§
Naming differences between eZ Publish 4.x and 5.x
eZ Publish 4.x eZ Publish 5.x
(Content) Class ContentType
(Content) Class Group ContentTypeGroup
(Content) Class Attribute FieldDefinition
(Content) Object Content (meta info in: ContentInfo)
(Content Object) Version VersionInfo
(Content Object) Attribute Field
(Content Object) Attribute content FieldValue
Datatype FieldType
Node Location
8. §
eZ Publish 5 can be extended thanks to the bundle system
§
A Bundle is a directory containing a set of files (PHP files, stylesheets,
JavaScripts, images, ...) that implement a single feature (a blog, a forum, etc)
and which can be easily shared with other developers.
§
eZ Publish 5 also provides a command line interface for generating a basic
bundle skeleton:
$ php ezpublish/console generate:bundle –namespace=eZ/TestBundle
13-4-26Presenter: Łukasz Serwatka Slide 8
Extending eZ Publish 5
9. 13-4-26Presenter: Łukasz Serwatka Slide 9
Extending eZ Publish 5§
Bundle Directory Structure
Bundle Directory Structure Description
Controller/ contains the controllers of the bundle (e.g.
HelloController.php);
DependencyInjection/ holds certain dependency injection extension classes,
which may import service configuration
Resources/config/ houses configuration, including routing configuration
(e.g. routing.yml);
Resources/views/ holds templates organized by controller name (e.g.
Hello/index.html.twig);
Resources/public/ contains web assets (images, stylesheets, etc) and is
copied or symbolically linked into the project web/
directory via the assets:install console command;
Tests/ holds all tests for the bundle.
10. 13-4-26Presenter: Łukasz Serwatka Slide 10
Extending eZ Publish 5§
Bundle Directory Structure – Advanced
Bundle Directory Structure Description
API/ contains the value object definitions, service
interfaces, etc. In short, public API interfaces provided
by your bundle.
Core/ holds field types implementation, persistence related
classes, repository implementations, signal-slot
implementations, etc.
SPI/ (Service Provider Interface) holds interfaces that can
contains one or several implementations around
Persistence (database), IO (file system), FieldTypes
(former DataTypes), Limitations (permissions system),
etc.
EventListeners/ holds event listeners implementation for both eZ
Publish 5 and LS
Command/ contains Console commands, each file must be
suffixed with Command.php
11. §
Example eZ Publish 5 Bundle architecture
13-4-26Presenter: Łukasz Serwatka Slide 11
Extending eZ Publish 5§
Bundle Directory Structure
13. §
Before a Bundle can be used it has to be registered in the system.
§
With the registerBundles() method, you have total control over which bundles
are used by eZ Publish 5 (including the core Symfony bundles).
// ezpublish/EzPublishKernel.php
public function registerBundles()
{
$bundles = array(
...,
// register your bundles
new eZTestBundleeZTestBundle(),
);
// ...
return $bundles;
}
13-4-26Presenter: <enter presenter Slide 13
Extending eZ Publish 5§
Registering Bundle
14. §
eZ Publish 5 provides a shortcut for automatic bundle registration
php ezpublish/console generate:bundle
--namespace=eZ/TestBundle
php ezpublish/console assets:install --symlink
php ezpublish/console cache:clear
13-4-26Presenter: Łukasz Serwatka Slide 14
Extending eZ Publish 5§
Registering Bundle
15. §
File: eZTestBundle.php
<?php
Namespace eZTestBundle;
use SymfonyComponentHttpKernelBundleBundle;
class eZTestBundle extends Bundle
{
public function getParent()
{
return ’eZDemoBundle';
}
}
13-4-26Presenter: Łukasz Serwatka Slide 15
Extending eZ Publish 5§
Bundle Override
16. §
File: src/eZ/DemoBundle/Controller/MyController.php
<?php
namespace eZDemoBundleMyController;
use EzSystemsDemoBundleControllerDemoController as BaseController;
class MyController extends BaseController
{
public function footerAction( $locationId )
{
// Call parent method or completely replace its logic with your own
$response = parent::footerAction( $locationId );
// ... do custom stuff
return $response;
}
}
§
Only works if the bundle refers to the controller using the standard
EzSystemsDemoBundle:Demo:footer syntax in routes and templates
13-4-26Presenter: Łukasz Serwatka Slide 16
Extending eZ Publish 5§
Controller Override
17. §
File: view.html.twig
<h1>Hello</h1>
<p>I’m a Twig template!</p>
§
Created Twig template can be included as follows:
{% include ‘eZTestBundle::view.html.twig’ %}
13-4-26Presenter: Łukasz Serwatka Slide 17
Extending eZ Publish 5§
Example Twig Template
18. §
Legacy template include
// eZ Publish 5.0
{% ez_legacy_include "design:parts/menu.tpl" with
{"current_node_id": location.contentInfo.mainLocationId}
%}
// eZ Publish 5.1 and above
{% include "design:parts/menu.tpl" with
{"current_node_id": location.contentInfo.mainLocationId}
%}
Note that if you pass Content or a Location it will be converted to the
corresponding eZ Publish Legacy objects.
13-4-26Presenter: Łukasz Serwatka Slide 18
Extending eZ Publish 5§
Working with legacy templates
19. §
The best practice for extension migration regarding configuration is to keep a
compatible format
ezoe.ini
[EditorSettings]
# Skin for the editor, 'default' and 'o2k7' is included as standard
Skin=o2k7
# Lets you control alignment of toolbar buttons [left|right]
ToolbarAlign=left
parameters:
# Namespace is ezoe (INI file was ezoe.ini), scope is defined to
ezdemo_site siteaccess
ezoe.ezdemo_site.EditorSettings.Skin: o2k7
ezoe.ezdemo_site.EditorSettings.ToolbarAlign: left
13-4-26Presenter: Łukasz Serwatka Slide 19
Extending eZ Publish 5§
Working with INI settings
20. // Assuming that the current siteaccess is ezdemo_site
// The following code will work whether you're using the legacy extension
or the migrated one.
$resolver = $this->getConfigResolver();
$skin = $resolver->getParameter( ’EditorSettings.Skin', ’ezoe' );
$toolbarAlign= $resolver->getParameter( ’EditorSettings.ToolbarAlign',
’ezoe' );
13-4-26Presenter: Łukasz Serwatka Slide 20
Extending eZ Publish 5§
Working with INI settings
21. §
Datatypes are FieldTypes in eZ Publish 5
§
Extends eZPublishCoreFieldTypeFieldType class
§
Uses Value objects for storing arbitrary data (extends
eZPublishCoreFieldTypeValue)
§
Requires converters for field values in legacy storage (implements
eZPublishCorePersistenceLegacyContentFieldValueConverter)
§
A NULL Converter is available for developers' convenience
§
Uses gateways for getting data from external storage (custom tables)
13-4-26Presenter: Łukasz Serwatka Slide 21
Extending eZ Publish 5§
FieldType
22. §
A common issue with rendering legacy field types in eZ Publish 5 is the
API_CONTENT_EXCEPTION
§
It occurs when the API throws an exception that could not be caught
internally (missing field type, missing converter, internal error...)
§
For simple field types, declaration of NULL converter is often a resolution
// Resources/config/fieldtypes.yml
ezpublish.fieldType.ezsample.class: %ezpublish.fieldType.eznull.class%
ezpublish.fieldType.ezsample:
class: %ezpublish.fieldType.ezsample.class%
parent: ezpublish.fieldType
arguments: [ ”ezsample" ]
tags:
- {name: ezpublish.fieldType, alias: ezsample}
13-4-26Presenter: Łukasz Serwatka Slide 22
Extending eZ Publish 5§
NULL Converter
24. §
Some FieldTypes store data in external data sources
§
Possible through the eZPublishSPIFieldTypeFieldStorage interface.
// Resources/config/fieldtypes.yml
parameters:
ezpublish.fieldType.ezsample.externalStorage.class:
eZPublishCoreFieldTypeSampleSampleStorage
services:
ezpublish.fieldType.ezsample.externalStorage:
class: %ezpublish.fieldType.ezsample.externalStorage.class%
tags:
- {name: ezpublish.fieldType.externalStorageHandler, alias:
ezsample}
13-4-26Presenter: Łukasz Serwatka Slide 24
Extending eZ Publish 5§
External storage
25. §
It is recommended to use gateway-based storage
§
Implement a gateway infrastructure and a registry for the gateways
§
Possible through the eZPublishCoreFieldTypeStorageGateway
// Resources/config/fieldtypes.yml
parameters:
ezpublish.fieldType.ezsample.storage_gateway.class:
eZPublishCoreFieldTypeSampleSampleStorageGatewayLegacyStorage
services:
ezpublish.fieldType.ezsample.storage_gateway:
class: %ezpublish.fieldType.ezsample.storage_gateway.class%
tags:
- {name: ezpublish.fieldType.externalStorageHandler.gateway,
alias: ezsample, identifier: LegacyStorage}
13-4-26Presenter: Łukasz Serwatka Slide 25
Extending eZ Publish 5§
External storage
26. abstract class Gateway extends StorageGateway
{
/**
* Stores data in the database based on the given field data
*
* @param eZPublishSPIPersistenceContentVersionInfo $versionInfo
* @param eZPublishSPIPersistenceContentField $field
*/
abstract public function storeFieldData( VersionInfo $versionInfo, Field $field );
/**
* Gets data stored in the field
*
* @param eZPublishSPIPersistenceContentVersionInfo $versionInfo
* @param eZPublishSPIPersistenceContentField $field
*/
abstract public function getFieldData( VersionInfo $versionInfo, Field $field );
/**
* Deletes field data for all $fieldIds in the version identified by
* $versionInfo.
*
* @param eZPublishSPIPersistenceContentVersionInfo $versionInfo
* @param array $fieldIds
*/
abstract public function deleteFieldData( VersionInfo $versionInfo, array $fieldIds );
} 13-4-26Presenter: Łukasz Serwatka Slide 26
Extending eZ Publish 5§
External storage
27. /**
* Deletes field data for all $fieldIds in the version identified by
* $versionInfo.
*
* @param eZPublishSPIPersistenceContentVersionInfo $versionInfo
* @param array $fieldIds
*/
public function deleteFieldData( VersionInfo $versionInfo, array $fieldIds )
{
$connection = $this->getConnection();
$query = $connection->createDeleteQuery();
$query
->deleteFrom( … )
->where(…)
$query->prepare()->execute();
}
13-4-26Presenter: Łukasz Serwatka Slide 27
Extending eZ Publish 5§
External storage
28. §
Possible to run some PHP code inside a sandbox through
the runCallback() method
<?php
// Declare use statements for the classes you may need
use eZINI;
// Inside a controller extending eZBundleEzPublishCoreBundleController
$settingName = 'MySetting';
$test = array( 'oneValue', 'anotherValue' );
$myLegacySetting = $this->getLegacyKernel()->runCallback(
function () use ( $settingName, $test )
{
// Here you can reuse $settingName and $test variables inside the legacy
context
$ini = eZINI::instance( 'someconfig.ini' );
return $ini->variable( 'SomeSection', $settingName );
}
);
13-4-26Presenter: Łukasz Serwatka Slide 28
Extending eZ Publish 5§
Running legacy code
29. §
Stored in the Resources/translations/ directory of the bundle.
§
Each translation file must be named according to the following path:
domain.locale.loader. For example Resources/translations/messages.fr.yml
§
Keyword messages preferred over messages that are written in the
language of the default locale. For example $t = $translator-
>trans(’ez5.great');
§
YAML is recommended configuration type
§
Possible to dump messages into the file with ezpublish/console
$ php ezpublish/console translation:update --output-
format=yml --dump-messages <locale> <bundle name>
13-4-26Presenter: Łukasz Serwatka Slide 29
Extending eZ Publish 5§
Translations
30. §
Commands should be placed under Command/ folder inside your Bundle
and file name must be suffixed with Command.php, e.g
EzTestCommand.php
Class EzTestCommand extends ContainerAwareCommand
{
protected function configure()
{
}
protected function execute(InputInterface $input, OutputInterface
$output)
{
}
}
13-4-26Presenter: Łukasz Serwatka Slide 30
Extending eZ Publish 5§
Console commands
32. §
Console command configuration
Class EzTestCommand extends ContainerAwareCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument(’first');
if ($name) {
$text = 'Hello '.$name;
}
if ($input->getOption(’second')) {
$text = strtoupper($text);
}
$output->writeln($text);
}
}
13-4-26Presenter: Łukasz Serwatka Slide 32
Extending eZ Publish 5§
Console commands
33. §
We recommend using composer (http://getcomposer.org) for bundles
installation
§
Provide packages via https://packagist.org website for ease of distribution
§
Configuration with composer.json
13-4-26Presenter: Łukasz Serwatka Slide 33
Extending eZ Publish 5§
Composer