SlideShare a Scribd company logo
eZ Platform, a headless CMS
1Madrid, @phpmad, 21/03/2018
#phpEz

About me
2
Carlos Revillo
https://twitter.com/crevillo
https://github.com/crevillo
https://linkedin.com/in/carlos-revillo
crevillo@gmail.com
carlos.revillo@the-cocktail.com
I work @ The Cocktail as a technology
team lead.
I started working with eZ Publish 10
years ago, while at Tanta.
Two times “Community member of the
year”
Agenda
3
About eZ Systems
1 2
ez Publish, the first
generation
eZ Platform, a
headless CMS
3 4 Success cases
About eZ Systems
1
4
eZ Systems, the company behind eZ Platform
5
1
eZ Systems was founded in Norway in 1999
They have a successful track record of 15 years as an open source
vendor.
Collaborations with more than 500 companies in 25 countries.
With a 45.000 member community, their partner
ecosystems comprises more than 80 companies.
Related links
● ez.no
● ez.no/Resources/Case-Studies
● ezplatform.com
● share.ez.no
● ez-community-on-slack.herokuapp.com
● github.com/ezsystems
● doc.ezplatform.com
eZ Publish, the first generation
2
6
eZ Publish was built around a very flexible data model...
7
2
★ The data model allows adding new content types
without modifying the database schema. Does
not implement the Active Record pattern.
★ 15 years later, this powerful data model remains
the same.
★ Contents are associated to locations, allowing for
“parent/child” relationships.
...but some issues were uncovered as time passed.
8
2
● Just like any other PHP project of the time, componentes
were dependent among themselves.
● There was no real separation between content and
presentation. The templates themselves triggered the
queries to the persistence layer -- database or Solr.
● A very steep learning curve.
● It was dependent on a custom framework, making it
difficult to integrate other third party libraries.
{def $nodes=fetch( 'content', 'tree',
hash( 'parent_node_id', 42 ) )}
{foreach $nodes as $node}
{$node.name|wash} <br />
{/foreach}
There was no other option than searching for an alternative
9
2
● Just like any other PHP project of the time, componentes
were dependent among themselves.
● There was no real separation between content and
presentation. The templates themselves triggered the
queries to the persistence layer -- database or Solr.
● A very steep learning curve.
● It was dependent on a custom framework, making it
difficult to integrate other third party libraries.
Why Symfony?
10
2
● It allows for backwards compatibility. You can even combine
Symfony controllers and legacy modules.
● Front end development teams can work with Twig directly without
having to learn a new API.
● Symfony developers will feel at home.
● You can integrate easily libraries and bundles that are not
developed specifically for eZ:
○ Liip
○ Fos Http Cache
○ ...
● There is a clear performance boost and better integration with
reverse proxies (like Varnish), search engines (Solr, ElasticSearch)
or key value stores like Redis or Memcache.
eZ Platform, a Headless CMS
3
11
Why a headless CMS in the first place?
12
3
★ In a Content-as-a-Service approach, the CMS is
focused in the backend features supporting the content
creators with the tools they need.
★ It’s all about helping the users with tasks like:
○ Content modelling
○ Content creation
○ Enabling collaboration between content creators
○ Content repository organization (content trees,
taxonomies…)
★ A headless CMS doesn’t care about how these contents
will be delivered or presented to end users.
Traditional CMS were focused on building websites
13
3
In a traditional CMS, the layers comprising page management and
content distribution are coupled.
There is no separation between how content is going to be
delivered and how content is going to be presented.
Headless CMSs are content centered.
14
3
In a headless CMS APIs allow for more options when delivering content.
… and why headless?
15
3
● Today, content is consumed and delivered
differently.
● We need to understand how content will be used
beyond the web.
eZ defines the following architecture for a headless eZ Platform
16
3
● The kernel is a business layer that gets exposed to
applications via a public API.
● The kernel defines the content repository, the search
API, and user and role management.
● The storage layer adds a caching layer between the
kernel and the database or filesystem.
● Developers will use the public API to build their
products.
● There is a RESTful API based on the public API that is
used to integrate eZ with other applications.
● You can customize the features of the platform using
Symfony and the public API -- if these features need
to be content-aware.
● Author’s note: in 10 years working with eZ I’ve never
written a custom SQL query.
Platform UI
TWIG Template Engine
Studio
Website REST API
xml/json
Symfony Framework
Public API
php
eZ Platform Kernel
Storage
Cache
Database Search IO
Extension
Anything Symfony
Extension
Custom API
Extension
Content Types
Field Types
New Modules
Extension
Custom API
Extension
Database
Search
Can
Admin, editors,
marketers (CMS users) End Users Web Services
Content Repo Search User Roles & Policy …
They decided to forget about CSS and JS.
17
3
● You are free to use whatever CSS or JS
framework you like with eZ Platform.
● All URLs are processed by a unique controller, no
matter the content type you want to show.
● This controller sends a given set of variables to
the relevant templates.
● This information is shown in the standard
Symfony Web Toolbar while developing your
project.
Several basic templates are included...
18
3
The page layout
<!doctype html>
<html lang="{{ app.request.locale|replace({'_': '-'}) }}">
<head>
<meta charset="utf-8">
{% if content is defined and title is not defined %}
{% set title = ez_content_name( content ) %}
{% endif %}
<title>{{ title|default( 'Home' ) }}</title>
<meta name="generator" content="eZ Platform"/>
{% if content is defined and content.contentInfo.mainLocationId %}
<link rel="canonical" href="{{ path( 'ez_urlalias', {'locationId': content.contentInfo.mainLocationId} ) }}" />
{% endif %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
★ The layout can be configured via settings.
★ The block called “content” will be written
by the specific template.
★ You can create as many different blocks as
needed.
{% extends noLayout == true ? viewbaseLayout : pagelayout %}
{% block content %}
<h2>{{ ez_content_name(content) }}</h2>
{% for field in content.fieldsByLanguage(language|default(null)) %}
<h3>{{ field.fieldDefIdentifier }}</h3>
{{ ez_render_field(content, field.fieldDefIdentifier) }}
{% endfor %}
{% endblock %}
19
3
Displaying content
{% block ezstring_field %}
{% spaceless %}
{% set field_value = field.value.text %}
{{ block( 'simple_inline_field' ) }}
{% endspaceless %}
{% endblock %}
{% block eztext_field %}
{% spaceless %}
{% set field_value = field.value|nl2br %}
{{ block( 'simple_block_field' ) }}
{% endspaceless %}
{% endblock %}
{% block ezrichtext_field %}
{%- set field_value = field.value.xml|richtext_to_html5 -%}
{{ block( 'simple_block_field' ) }}
{% endblock %}
{% block simple_inline_field %}
{% spaceless %}
{% if field_value is not defined %}
{% set field_value = field.value %}
{% endif %}
<span {{ block( 'field_attributes' ) }}>{{ field_value }}</span>
{% endspaceless %}
{% endblock %}
eZ doesn’t store HTML, but XML. In this way
you can delivery HTML or whatever format
needed by transformations.
… that just contain certain specific tags...
… with additional ways to help with template customization...
20
3
The templates to be used are defined via configuration file, to help with the customization of the view layer.
content_view:
full:
home:
template: "@ezdesign/full/home.html.twig"
params:
place_list_location_id: '%app.home.place_list_location_id%'
tastes_location_id: '%app.home.tastes_location_id%'
match:
IdLocation: 2
IdentifierContentType: [folder]
article:
template: "@ezdesign/full/article.html.twig"
match:
IdentifierContentType: [article]
line:
blog_post:
template: “@ezdesign/line/blog_post.html.twig”
match:
IdentifierContentType: [blog_post]
The template to be used will be determined by one or several
configured conditions that must be verified by the content to be
shown.
These templates can be overwritten depending on the view (full,
line, foo, bar…)
Note: @ezdesign is a special annotation useful for multisites. See the dedicated
section.
article.html.twig
<div class="meta">
<span class="field-author"> {{ ez_field_value(content, 'author') }} </span>
<span class="field-date"> <time pubdate datetime="{{ ez_field_value(content,
‘publish_date')|date("Y-m-d") }}">{{ ez_field_value(content,
'publish_date')|date("d M Y") }}</time></span>
</div>
...or with specific Symfony controllers for each case
21
3
content_view:
full:
subscribe:
controller: app.controller.contactform:showContactFormAction
template: "@ezdesign/full/subscribe.html.twig"
match:
IdentifierContentType: [subscribe]
blog:
controller: "ez_query:contentQueryAction"
template: "@ezdesign/full/blog.html.twig"
match:
IdentifierContentType: [blog]
params:
query:
query_type: "AppBundle:Children"
parameters:
parent_location_id: "@=location.id"
assign_results_to: children
The controllers can send variables to the templates.
eZ exposes a controller that can execute a given query defined by the developer and will
assign the results to a variable.
https://doc.ezplatform.com/en/latest/guide/content_rendering/#querytype-example-latest-content
public function showContactFormAction(View $view, Request $request)
{
$form = $this->formFactory->create(ContactType::class);
if ($request->isMethod('POST')) {
// other logic
}
$view->addParameters([
'form' => $form->createView(),
]);
return $view;
}
<div class="children"> {* extract from blog.html.twig *}
{% for child in children.searchHits %}
<div class="container">
{{ render_esi(controller('ez_content:viewAction', {
locationId: child.valueObject.contentInfo.mainLocationId,
contentId: child.valueObject.contentInfo.id, viewType: 'line'
})) }}
</div>
{% endfor %}
</div>
eZ Platform shines on the granularity of its permission model
22
3
● Users are content too!
● They are usually organized into “user groups”, which are also
content.
● A role defines a set of policies which a given user has access to.
● A policy will be defined by a module, one or several functions,
and, optionally, some limitations.
● User groups can be assigned to roles, and individual users will
inherit the permissions assigned to their group.
● Roles can also be assigned specifically to a given user.
Everything is content in eZ, and there is an API to discover it
programatically.
23
3
● eZ can work with 3 search engines:
○ Database
○ Solr
○ ElasticSearch (experimental)
● These engines feature “fulltext search”, as well as filtered search,
and sorting by different criteria.
● Everything is content in eZ, so everything you build will depend
on how this content is organized:
○ Menus
○ Listings
○ ...
● You can switch search engines with minimal impact in the
codebase.
$query = new eZPublishAPIRepositoryValuesContentQuery();
$query->criterion = new CriterionLogicalAnd([
new CriterionParentLocationId(43),
new CriterionContentTypeIdentifier('product')
]);
$query->sortClauses = [
new SortClauseDatePublished(Query::SORT_DESC)
]);
$query->offset =10;
$query->limit = 5;
$result = $searchService->findContent( $query );
Results can be obtained by using different filtering and sorting criteria
24
3
● eZ Platform supports the Symfony Reverse Proxy by default and has full integration with Varnish.
● When content gets created or updated, eZ will tell Varnish that there are stale content objects that need to be
refreshed. (cache invalidation)
● eZ provides a Varnish VCL to help with this:
https://github.com/ezsystems/ezplatform/blob/master/doc/varnish/vcl/varnish4_xkey.vcl
● This VCL can make Varnish serve the same cached page to different users.
● Our own controllers can set a Vary header to show the same content to users with the same policies:
use SymfonyComponentHttpFoundationResponse;
// En tu controlador
$response = new Response();
$response->setVary( 'X-User-Hash' );
eZ Platform is all about performance
25
3
● This approach is based on the article Context aware HTTP caching.
● More info: https://github.com/ezsystems/ezplatform-http-cache/blob/master/docs/fos_http_cache.
A fine tuned VCL file
26
3
X-User-Hash
1 2
34
1 Varnish receives the HTTP request (without X-User-Hash) 2 Varnish does an origin request with the following headers:
● `X-HTTP-Override: AUTHENTICATE`
● `Accept: application/vnd.ez.UserHash+text`
● Original cookie
3 eZ returns a response with X-User-Hash4 Varnish adds the X-User-Hash header to the original request.
Serving several sites with the same installation is a breeze with eZ Platform
33
27
Root
Location ID: 1
Site A
Location ID: 2
Site B
Location ID: 3
Section B
Location ID: 5
Section C
Location ID: 6
Section 1
Location ID: 7
Section 2 &
Site C
Location ID: 8
Subsection 1
Location ID: 9
Subsection 2
Location ID: 10
www.siteA.com www.siteB.com www.siteC.com www.siteC.com/en
★ Sites can share settings and
content.
★ These configuration can also be
customized on a per-site basis.
★ This feature also allows for
multi-language versions for each
site.
ezpublish:
siteaccess:
list: [es, eng, other, foo, bar]
default_siteaccess: es
match:
URIElement: 1
● A siteaccess is a group of settings that will be used when
you access the site with a particular URL.
● There are different matchers that will determine the
siteaccess to be used.
● There are several built-in matchers
○ URIElement
○ URIText
○ HostElement
○ HostText
○ MapHost
○ MapURI
○ RegexURI
○ etc
More info:
https://doc.ezplatform.com/en/2.0/guide/siteaccess/
You can host subdomains or different domains altogether.
28
3
ezpublish:
siteaccess:
match:
MapHost:
www.foo.com: foo_front
adm.foo.com: foo_admin
www.bar-stuff.fr: bar_front
adm.bar-stuff.fr: bar_admin
ezpublish:
siteaccess:
match:
RegexURI:
regex: "^/foo(w+)bar"
# Default is 1
itemNumber: 1
ezpublish:
siteaccess:
match:
MapURI:
es: site_espana
fr: site_europa
en: site_europa
other: other_siteaccess
ezpublish:
siteaccess:
match:
URIText:
prefix: foo
suffix: bar
ezdesign:
# You declare all available designs under "design_list".
design_list:
# my_design will be composed of "theme1" and "theme2"
# "theme1" will be tried first. If a template cannot be found in "theme1", "theme2" will be
tried out.
my_design: [theme1, theme2]
ezpublish:
# ...
system:
my_siteaccess:
# my_siteaccess will use "my_design"
design: my_design
● siteaccess can be organized into groups and share some
or all of their settings.
● For example, all the sites can share the same database or
each site can have its own.
● They can also share all the templates, some of them, or
none.
● Every siteaccess can configure which languages will be
applied.
And you can customize the design o the languages to be
shown
29
3
eZ Platform will take care of showing the translated version or the
correct template without changing the code.
ezpublish:
system:
# Configuration for the 'eng' SiteAccess
eng:
languages: [eng-GB]
esl:
languages: [esl-ES, eng-GB]
Success cases
4
30
Kitchen Aid
31
4
The same content is used when serving the website, mobile apps,
printed recipe books and to show the recipes in the kitchen
appliance.
Add garlic,
peas and
ham
Viking Line
32
4
● Developed by Ixonos
● “Each ship of Viking Line fleet is unique which
means that service contents must be easily
customizable both by the crew and the land
organization.”
● “eZ was implemented as the content
management solution for the on-board digital
platform. Content from eZ is displayed
on-board Viking Line ships for mobile app,
browser UI, in-cabin TV’s and digital signage
screens.”
https://ez.no/Blog/Ixonos-creates-innovative-app-with-eZ-Publish-Platform-for-Viking-Line-passengers
Mikko Sjöblom,
Business Director at Ixonos
Borussia Dortmund
33
4
https://ez.no/Blog/Case-Study-BVB-A-premier-football-club-with-clear-goals
● Developed by the soccer team’s own IT team.
● Every business team (marketing, ticketing, news
editors... ) has specific accesses and can work
independently.
● Best Champions League teams website in 2014 (up
from position 29 of 30 in 2013)
http://www.championsleaguewebsites.com/2014/
● The same repository serves content for web, apps,
iOS or Android and even displays in
Westfalenstadion, now Signal Iduna Park.

Movistar Originals
34
4
● Developed by The Cocktail
● All sites are served by the same installation and share
databases and cloud infrastructure.
● The multisite capabilities allowed the reuse of HTML
structures and the Symfony controllers to create new
sites.
● Adding a new site is an easy process that doesn’t
require working in the software (only stylesheets)
http://originales.movistarplus.es
35

Pulley and
me thank
you for
viewing this.

Graphics by Hakan Ertan. Thanks so much to Bertrand Maugain, rest of the
eZ Crew and the #ezcommunity for their invaluable help all these years.
English translation by Juan Lupión

More Related Content

PPSX
Advanced PHP Web Development Tools in 2015
PDF
Object Oriented Programming with Laravel - Session 1
PDF
Asp.netrole
PDF
Object Oriented Programming with Laravel - Session 3
PPT
Tech talk webtech
PDF
PDF
Web Design & Development - Session 7
PDF
Crash Course HTML/Rails Slides
Advanced PHP Web Development Tools in 2015
Object Oriented Programming with Laravel - Session 1
Asp.netrole
Object Oriented Programming with Laravel - Session 3
Tech talk webtech
Web Design & Development - Session 7
Crash Course HTML/Rails Slides

What's hot (6)

PPT
Tech talk php_cms
PPTX
PDF
POX to HATEOAS: Our Company's Journey Building a Hypermedia API
PPT
PHP Project PPT
PDF
Php & mysql course syllabus
PPTX
PHP Summer Training Presentation
Tech talk php_cms
POX to HATEOAS: Our Company's Journey Building a Hypermedia API
PHP Project PPT
Php & mysql course syllabus
PHP Summer Training Presentation
Ad

Similar to Ez platform meetup, madrid 21 marzo 2018 english (20)

PDF
Ny symfony meetup may 2015
PDF
Unleash your Symfony projects with eZ Platform
PDF
Using eZ Platform as a Headless CMS (with Vue.js)
PPTX
Content Management Systems and Refactoring - Drupal, WordPress and eZ Publish
PDF
Product workshop slides
PDF
eZ Systems Product Workshop Slides
PDF
Start with Bolt and Go Ez - eZ Publish Summer Camp 2015
PDF
eZPublish meets Simfony2 - phpDay2013
PDF
eZ Publish 5 in depth inspection
PDF
PHP Benelux 2017 - Caching The Right Way
PDF
Introduction to eZ Platform v2 UI Customization
PDF
eZ in the Year Ahead
PDF
eZ Platform and eZ Studio: Where We Are, Where We Are Going, and a Look Towar...
PDF
Look Towards 2.0 and Beyond - eZ Conference 2016
PPTX
Symfony2 for legacy app rejuvenation: the eZ Publish case study
PDF
What's brewing in the eZ Systems extensions kitchen
PDF
eZ Publish Norwegian Public User Group
PDF
eZ publish - Instant Publishing and Greater Traffic
PDF
eZ Accelerator v1
PDF
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
Ny symfony meetup may 2015
Unleash your Symfony projects with eZ Platform
Using eZ Platform as a Headless CMS (with Vue.js)
Content Management Systems and Refactoring - Drupal, WordPress and eZ Publish
Product workshop slides
eZ Systems Product Workshop Slides
Start with Bolt and Go Ez - eZ Publish Summer Camp 2015
eZPublish meets Simfony2 - phpDay2013
eZ Publish 5 in depth inspection
PHP Benelux 2017 - Caching The Right Way
Introduction to eZ Platform v2 UI Customization
eZ in the Year Ahead
eZ Platform and eZ Studio: Where We Are, Where We Are Going, and a Look Towar...
Look Towards 2.0 and Beyond - eZ Conference 2016
Symfony2 for legacy app rejuvenation: the eZ Publish case study
What's brewing in the eZ Systems extensions kitchen
eZ Publish Norwegian Public User Group
eZ publish - Instant Publishing and Greater Traffic
eZ Accelerator v1
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
Ad

Recently uploaded (20)

PPTX
The-Looming-Shadow-How-AI-Poses-Dangers-to-Humanity.pptx
PPTX
Lesson 3_Tessellation.pptx finite Mathematics
DOCX
573137875-Attendance-Management-System-original
PDF
Embodied AI: Ushering in the Next Era of Intelligent Systems
PPTX
24AI201_AI_Unit_4 (1).pptx Artificial intelligence
PDF
Queuing formulas to evaluate throughputs and servers
PPTX
web development for engineering and engineering
PDF
Model Code of Practice - Construction Work - 21102022 .pdf
PDF
Evaluating the Democratization of the Turkish Armed Forces from a Normative P...
PPTX
Unit 5 BSP.pptxytrrftyyydfyujfttyczcgvcd
PPTX
Recipes for Real Time Voice AI WebRTC, SLMs and Open Source Software.pptx
PPTX
Practice Questions on recent development part 1.pptx
PPTX
anatomy of limbus and anterior chamber .pptx
PDF
July 2025 - Top 10 Read Articles in International Journal of Software Enginee...
PDF
Geotechnical Engineering, Soil mechanics- Soil Testing.pdf
PPTX
UNIT-1 - COAL BASED THERMAL POWER PLANTS
PPTX
Strings in CPP - Strings in C++ are sequences of characters used to store and...
PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PPTX
Fluid Mechanics, Module 3: Basics of Fluid Mechanics
The-Looming-Shadow-How-AI-Poses-Dangers-to-Humanity.pptx
Lesson 3_Tessellation.pptx finite Mathematics
573137875-Attendance-Management-System-original
Embodied AI: Ushering in the Next Era of Intelligent Systems
24AI201_AI_Unit_4 (1).pptx Artificial intelligence
Queuing formulas to evaluate throughputs and servers
web development for engineering and engineering
Model Code of Practice - Construction Work - 21102022 .pdf
Evaluating the Democratization of the Turkish Armed Forces from a Normative P...
Unit 5 BSP.pptxytrrftyyydfyujfttyczcgvcd
Recipes for Real Time Voice AI WebRTC, SLMs and Open Source Software.pptx
Practice Questions on recent development part 1.pptx
anatomy of limbus and anterior chamber .pptx
July 2025 - Top 10 Read Articles in International Journal of Software Enginee...
Geotechnical Engineering, Soil mechanics- Soil Testing.pdf
UNIT-1 - COAL BASED THERMAL POWER PLANTS
Strings in CPP - Strings in C++ are sequences of characters used to store and...
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
Fluid Mechanics, Module 3: Basics of Fluid Mechanics

Ez platform meetup, madrid 21 marzo 2018 english

  • 1. eZ Platform, a headless CMS 1Madrid, @phpmad, 21/03/2018 #phpEz
  • 3. Agenda 3 About eZ Systems 1 2 ez Publish, the first generation eZ Platform, a headless CMS 3 4 Success cases
  • 5. eZ Systems, the company behind eZ Platform 5 1 eZ Systems was founded in Norway in 1999 They have a successful track record of 15 years as an open source vendor. Collaborations with more than 500 companies in 25 countries. With a 45.000 member community, their partner ecosystems comprises more than 80 companies. Related links ● ez.no ● ez.no/Resources/Case-Studies ● ezplatform.com ● share.ez.no ● ez-community-on-slack.herokuapp.com ● github.com/ezsystems ● doc.ezplatform.com
  • 6. eZ Publish, the first generation 2 6
  • 7. eZ Publish was built around a very flexible data model... 7 2 ★ The data model allows adding new content types without modifying the database schema. Does not implement the Active Record pattern. ★ 15 years later, this powerful data model remains the same. ★ Contents are associated to locations, allowing for “parent/child” relationships.
  • 8. ...but some issues were uncovered as time passed. 8 2 ● Just like any other PHP project of the time, componentes were dependent among themselves. ● There was no real separation between content and presentation. The templates themselves triggered the queries to the persistence layer -- database or Solr. ● A very steep learning curve. ● It was dependent on a custom framework, making it difficult to integrate other third party libraries. {def $nodes=fetch( 'content', 'tree', hash( 'parent_node_id', 42 ) )} {foreach $nodes as $node} {$node.name|wash} <br /> {/foreach}
  • 9. There was no other option than searching for an alternative 9 2 ● Just like any other PHP project of the time, componentes were dependent among themselves. ● There was no real separation between content and presentation. The templates themselves triggered the queries to the persistence layer -- database or Solr. ● A very steep learning curve. ● It was dependent on a custom framework, making it difficult to integrate other third party libraries.
  • 10. Why Symfony? 10 2 ● It allows for backwards compatibility. You can even combine Symfony controllers and legacy modules. ● Front end development teams can work with Twig directly without having to learn a new API. ● Symfony developers will feel at home. ● You can integrate easily libraries and bundles that are not developed specifically for eZ: ○ Liip ○ Fos Http Cache ○ ... ● There is a clear performance boost and better integration with reverse proxies (like Varnish), search engines (Solr, ElasticSearch) or key value stores like Redis or Memcache.
  • 11. eZ Platform, a Headless CMS 3 11
  • 12. Why a headless CMS in the first place? 12 3 ★ In a Content-as-a-Service approach, the CMS is focused in the backend features supporting the content creators with the tools they need. ★ It’s all about helping the users with tasks like: ○ Content modelling ○ Content creation ○ Enabling collaboration between content creators ○ Content repository organization (content trees, taxonomies…) ★ A headless CMS doesn’t care about how these contents will be delivered or presented to end users.
  • 13. Traditional CMS were focused on building websites 13 3 In a traditional CMS, the layers comprising page management and content distribution are coupled. There is no separation between how content is going to be delivered and how content is going to be presented.
  • 14. Headless CMSs are content centered. 14 3 In a headless CMS APIs allow for more options when delivering content.
  • 15. … and why headless? 15 3 ● Today, content is consumed and delivered differently. ● We need to understand how content will be used beyond the web.
  • 16. eZ defines the following architecture for a headless eZ Platform 16 3 ● The kernel is a business layer that gets exposed to applications via a public API. ● The kernel defines the content repository, the search API, and user and role management. ● The storage layer adds a caching layer between the kernel and the database or filesystem. ● Developers will use the public API to build their products. ● There is a RESTful API based on the public API that is used to integrate eZ with other applications. ● You can customize the features of the platform using Symfony and the public API -- if these features need to be content-aware. ● Author’s note: in 10 years working with eZ I’ve never written a custom SQL query. Platform UI TWIG Template Engine Studio Website REST API xml/json Symfony Framework Public API php eZ Platform Kernel Storage Cache Database Search IO Extension Anything Symfony Extension Custom API Extension Content Types Field Types New Modules Extension Custom API Extension Database Search Can Admin, editors, marketers (CMS users) End Users Web Services Content Repo Search User Roles & Policy …
  • 17. They decided to forget about CSS and JS. 17 3 ● You are free to use whatever CSS or JS framework you like with eZ Platform. ● All URLs are processed by a unique controller, no matter the content type you want to show. ● This controller sends a given set of variables to the relevant templates. ● This information is shown in the standard Symfony Web Toolbar while developing your project.
  • 18. Several basic templates are included... 18 3 The page layout <!doctype html> <html lang="{{ app.request.locale|replace({'_': '-'}) }}"> <head> <meta charset="utf-8"> {% if content is defined and title is not defined %} {% set title = ez_content_name( content ) %} {% endif %} <title>{{ title|default( 'Home' ) }}</title> <meta name="generator" content="eZ Platform"/> {% if content is defined and content.contentInfo.mainLocationId %} <link rel="canonical" href="{{ path( 'ez_urlalias', {'locationId': content.contentInfo.mainLocationId} ) }}" /> {% endif %} </head> <body> {% block content %}{% endblock %} </body> </html> ★ The layout can be configured via settings. ★ The block called “content” will be written by the specific template. ★ You can create as many different blocks as needed.
  • 19. {% extends noLayout == true ? viewbaseLayout : pagelayout %} {% block content %} <h2>{{ ez_content_name(content) }}</h2> {% for field in content.fieldsByLanguage(language|default(null)) %} <h3>{{ field.fieldDefIdentifier }}</h3> {{ ez_render_field(content, field.fieldDefIdentifier) }} {% endfor %} {% endblock %} 19 3 Displaying content {% block ezstring_field %} {% spaceless %} {% set field_value = field.value.text %} {{ block( 'simple_inline_field' ) }} {% endspaceless %} {% endblock %} {% block eztext_field %} {% spaceless %} {% set field_value = field.value|nl2br %} {{ block( 'simple_block_field' ) }} {% endspaceless %} {% endblock %} {% block ezrichtext_field %} {%- set field_value = field.value.xml|richtext_to_html5 -%} {{ block( 'simple_block_field' ) }} {% endblock %} {% block simple_inline_field %} {% spaceless %} {% if field_value is not defined %} {% set field_value = field.value %} {% endif %} <span {{ block( 'field_attributes' ) }}>{{ field_value }}</span> {% endspaceless %} {% endblock %} eZ doesn’t store HTML, but XML. In this way you can delivery HTML or whatever format needed by transformations. … that just contain certain specific tags...
  • 20. … with additional ways to help with template customization... 20 3 The templates to be used are defined via configuration file, to help with the customization of the view layer. content_view: full: home: template: "@ezdesign/full/home.html.twig" params: place_list_location_id: '%app.home.place_list_location_id%' tastes_location_id: '%app.home.tastes_location_id%' match: IdLocation: 2 IdentifierContentType: [folder] article: template: "@ezdesign/full/article.html.twig" match: IdentifierContentType: [article] line: blog_post: template: “@ezdesign/line/blog_post.html.twig” match: IdentifierContentType: [blog_post] The template to be used will be determined by one or several configured conditions that must be verified by the content to be shown. These templates can be overwritten depending on the view (full, line, foo, bar…) Note: @ezdesign is a special annotation useful for multisites. See the dedicated section. article.html.twig <div class="meta"> <span class="field-author"> {{ ez_field_value(content, 'author') }} </span> <span class="field-date"> <time pubdate datetime="{{ ez_field_value(content, ‘publish_date')|date("Y-m-d") }}">{{ ez_field_value(content, 'publish_date')|date("d M Y") }}</time></span> </div>
  • 21. ...or with specific Symfony controllers for each case 21 3 content_view: full: subscribe: controller: app.controller.contactform:showContactFormAction template: "@ezdesign/full/subscribe.html.twig" match: IdentifierContentType: [subscribe] blog: controller: "ez_query:contentQueryAction" template: "@ezdesign/full/blog.html.twig" match: IdentifierContentType: [blog] params: query: query_type: "AppBundle:Children" parameters: parent_location_id: "@=location.id" assign_results_to: children The controllers can send variables to the templates. eZ exposes a controller that can execute a given query defined by the developer and will assign the results to a variable. https://doc.ezplatform.com/en/latest/guide/content_rendering/#querytype-example-latest-content public function showContactFormAction(View $view, Request $request) { $form = $this->formFactory->create(ContactType::class); if ($request->isMethod('POST')) { // other logic } $view->addParameters([ 'form' => $form->createView(), ]); return $view; } <div class="children"> {* extract from blog.html.twig *} {% for child in children.searchHits %} <div class="container"> {{ render_esi(controller('ez_content:viewAction', { locationId: child.valueObject.contentInfo.mainLocationId, contentId: child.valueObject.contentInfo.id, viewType: 'line' })) }} </div> {% endfor %} </div>
  • 22. eZ Platform shines on the granularity of its permission model 22 3 ● Users are content too! ● They are usually organized into “user groups”, which are also content. ● A role defines a set of policies which a given user has access to. ● A policy will be defined by a module, one or several functions, and, optionally, some limitations. ● User groups can be assigned to roles, and individual users will inherit the permissions assigned to their group. ● Roles can also be assigned specifically to a given user.
  • 23. Everything is content in eZ, and there is an API to discover it programatically. 23 3 ● eZ can work with 3 search engines: ○ Database ○ Solr ○ ElasticSearch (experimental) ● These engines feature “fulltext search”, as well as filtered search, and sorting by different criteria. ● Everything is content in eZ, so everything you build will depend on how this content is organized: ○ Menus ○ Listings ○ ... ● You can switch search engines with minimal impact in the codebase.
  • 24. $query = new eZPublishAPIRepositoryValuesContentQuery(); $query->criterion = new CriterionLogicalAnd([ new CriterionParentLocationId(43), new CriterionContentTypeIdentifier('product') ]); $query->sortClauses = [ new SortClauseDatePublished(Query::SORT_DESC) ]); $query->offset =10; $query->limit = 5; $result = $searchService->findContent( $query ); Results can be obtained by using different filtering and sorting criteria 24 3
  • 25. ● eZ Platform supports the Symfony Reverse Proxy by default and has full integration with Varnish. ● When content gets created or updated, eZ will tell Varnish that there are stale content objects that need to be refreshed. (cache invalidation) ● eZ provides a Varnish VCL to help with this: https://github.com/ezsystems/ezplatform/blob/master/doc/varnish/vcl/varnish4_xkey.vcl ● This VCL can make Varnish serve the same cached page to different users. ● Our own controllers can set a Vary header to show the same content to users with the same policies: use SymfonyComponentHttpFoundationResponse; // En tu controlador $response = new Response(); $response->setVary( 'X-User-Hash' ); eZ Platform is all about performance 25 3
  • 26. ● This approach is based on the article Context aware HTTP caching. ● More info: https://github.com/ezsystems/ezplatform-http-cache/blob/master/docs/fos_http_cache. A fine tuned VCL file 26 3 X-User-Hash 1 2 34 1 Varnish receives the HTTP request (without X-User-Hash) 2 Varnish does an origin request with the following headers: ● `X-HTTP-Override: AUTHENTICATE` ● `Accept: application/vnd.ez.UserHash+text` ● Original cookie 3 eZ returns a response with X-User-Hash4 Varnish adds the X-User-Hash header to the original request.
  • 27. Serving several sites with the same installation is a breeze with eZ Platform 33 27 Root Location ID: 1 Site A Location ID: 2 Site B Location ID: 3 Section B Location ID: 5 Section C Location ID: 6 Section 1 Location ID: 7 Section 2 & Site C Location ID: 8 Subsection 1 Location ID: 9 Subsection 2 Location ID: 10 www.siteA.com www.siteB.com www.siteC.com www.siteC.com/en ★ Sites can share settings and content. ★ These configuration can also be customized on a per-site basis. ★ This feature also allows for multi-language versions for each site. ezpublish: siteaccess: list: [es, eng, other, foo, bar] default_siteaccess: es match: URIElement: 1
  • 28. ● A siteaccess is a group of settings that will be used when you access the site with a particular URL. ● There are different matchers that will determine the siteaccess to be used. ● There are several built-in matchers ○ URIElement ○ URIText ○ HostElement ○ HostText ○ MapHost ○ MapURI ○ RegexURI ○ etc More info: https://doc.ezplatform.com/en/2.0/guide/siteaccess/ You can host subdomains or different domains altogether. 28 3 ezpublish: siteaccess: match: MapHost: www.foo.com: foo_front adm.foo.com: foo_admin www.bar-stuff.fr: bar_front adm.bar-stuff.fr: bar_admin ezpublish: siteaccess: match: RegexURI: regex: "^/foo(w+)bar" # Default is 1 itemNumber: 1 ezpublish: siteaccess: match: MapURI: es: site_espana fr: site_europa en: site_europa other: other_siteaccess ezpublish: siteaccess: match: URIText: prefix: foo suffix: bar
  • 29. ezdesign: # You declare all available designs under "design_list". design_list: # my_design will be composed of "theme1" and "theme2" # "theme1" will be tried first. If a template cannot be found in "theme1", "theme2" will be tried out. my_design: [theme1, theme2] ezpublish: # ... system: my_siteaccess: # my_siteaccess will use "my_design" design: my_design ● siteaccess can be organized into groups and share some or all of their settings. ● For example, all the sites can share the same database or each site can have its own. ● They can also share all the templates, some of them, or none. ● Every siteaccess can configure which languages will be applied. And you can customize the design o the languages to be shown 29 3 eZ Platform will take care of showing the translated version or the correct template without changing the code. ezpublish: system: # Configuration for the 'eng' SiteAccess eng: languages: [eng-GB] esl: languages: [esl-ES, eng-GB]
  • 31. Kitchen Aid 31 4 The same content is used when serving the website, mobile apps, printed recipe books and to show the recipes in the kitchen appliance. Add garlic, peas and ham
  • 32. Viking Line 32 4 ● Developed by Ixonos ● “Each ship of Viking Line fleet is unique which means that service contents must be easily customizable both by the crew and the land organization.” ● “eZ was implemented as the content management solution for the on-board digital platform. Content from eZ is displayed on-board Viking Line ships for mobile app, browser UI, in-cabin TV’s and digital signage screens.” https://ez.no/Blog/Ixonos-creates-innovative-app-with-eZ-Publish-Platform-for-Viking-Line-passengers Mikko Sjöblom, Business Director at Ixonos
  • 33. Borussia Dortmund 33 4 https://ez.no/Blog/Case-Study-BVB-A-premier-football-club-with-clear-goals ● Developed by the soccer team’s own IT team. ● Every business team (marketing, ticketing, news editors... ) has specific accesses and can work independently. ● Best Champions League teams website in 2014 (up from position 29 of 30 in 2013) http://www.championsleaguewebsites.com/2014/ ● The same repository serves content for web, apps, iOS or Android and even displays in Westfalenstadion, now Signal Iduna Park.
  • 34.  Movistar Originals 34 4 ● Developed by The Cocktail ● All sites are served by the same installation and share databases and cloud infrastructure. ● The multisite capabilities allowed the reuse of HTML structures and the Symfony controllers to create new sites. ● Adding a new site is an easy process that doesn’t require working in the software (only stylesheets) http://originales.movistarplus.es
  • 35. 35  Pulley and me thank you for viewing this.  Graphics by Hakan Ertan. Thanks so much to Bertrand Maugain, rest of the eZ Crew and the #ezcommunity for their invaluable help all these years. English translation by Juan Lupión