Message-ID: <1568458848.2830.1485850931143.JavaMail.confluence@ip-10-127-227-164> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_2829_1501512143.1485850931142" ------=_Part_2829_1501512143.1485850931142 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
The backend interface is produced by the Platfor= mUI Bundle which provides a JavaScript Single Page Application based on= the YUI App Framework. This application is accessible in= your browser at http://[uri_of_platform]/ez.
The PlatformUI application code is divided into different types of compo= nents:
The following chart depicts the interaction between those components:
The views represent a large part of the application and each of them can= be used in three different contexts:
A view used as a main view is configured at the route level to be displa= yed when the user navigates to that route.
For instance, when reaching /ez
, the user is redirected to =
the loginForm
route (/ez#/login
) and this route i=
s configured in the following way in the application component:
{ name: "loginForm", path: "/login", service: Y.eZ.LoginFormViewService, sideViews: {'navigationHub': false, 'discoveryBar'= : false}, view: 'loginFormView', callbacks: ['open', 'handleSideViews', 'handleMain= View'] }=20
Among others things, this means the view loginFormView
will=
be used as the main view when this route is matched. loginFormView=
code> is actually the identifier of the view =
metadata registered in the
view
property of the Application.
To avoid having huge main views doing too many things in the application= , the views are divided into smaller parts called sub-views.
For instance, the view used to display a Location is divided into severa= l views at several levels, it contains:
A view can also be used as a side view. As its name suggests a side view= can represent anything that is not part of the main view.
For instance, when displaying a Location, the top menu (the Navigation h= ub) or the left toolbar (the Discovery Bar) are side views.
The side views are also used for various widgets providing a service use= d several times in the application, such as the Universal Discovery Widget.=
The view services act between the Application and the Views for both the= main views and the side views. They are responsible for providing the requ= ired data needed by a main view or a side view to be rendered. A view servi= ce will also receive the events triggered by the view to react or provide t= he additional data. For that, the view services receive an instance of the = JavaScript REST Client.
Depending on the part of the PlatformUI Application you are using, the p= age may be generated in two different ways. From an end-user perspective, t= his is almost transparent but as a developer it is important to understand = how the page is generated to be able to extend it.
The pages in the content part (as opposed to admin related pages) are fu= lly rendered in the browser. For instance, when displaying a Location in Pl= atformUI, the corresponding view service loads the Location model and the <= em>related models (Content, Content Type, etc.) with the eZ Platform R= EST API (through the JavaScript REST Client) and gives them the LocationVie= w to be displayed directly by this view and/or by its sub-views. If you ope= n the browser developer tools in the network panel, you can see the REST re= quests needed to build the page and they only contain a JSON structure.
<= /p>
The pages in the admin are build in a more traditional way as they are p= artly rendered server side. For those pages, the view service fetches one (= or several) HTML fragment(s) from the server. This HTML fragment follows a = very simple structure and can be generated by any means on the server and o= f course, in PlatformUI this is done in a quite standard Symfony controller= . By opening the browser developer tools in the network panel you can see t= he requests needed to build the section list page.
The Navigation Hub is a side view displaying the top menu.
It displays 4 Navigation zones:
A zone can contain an arbitrary number of Navigation zone items<= /strong>. By default, the Content zone has 2 navigation items: Content structure and Media library.
Bar views provide a set of potential actions for the user.
When navigating in the Content zone, the Discovery Bar View allows you to discover content while the Action Bar View on the right allows you to act on the Content item being viewed (edit, = move, copy, etc.).
When editing a Content item, the Edit Action Bar View o= n the right allows you to act on the Content item being edited.
The Universal Discovery Widget is a side view triggered when the user ne= eds to pick a Content item (or a Location). It can provide several = Discovery Methods. By default, Browse and Search= are available.
V1.4=
eZ Platform contains a Dashboard which shows the user the most relevant = Content items divided into blocks for a quick overview.
Aside from the built-in blocks you can extend the Dashboard with new one= s and remove existing ones.
It can be done in four steps:
Create a plugin for the view
Add modules to configuration
The first step is creating a view that will be added to the Dashboard. Y= ou can do it based on the Dashboard Block Asynchronous View. Thanks to this= you only need to provide the data to display in the table.
Using the Dashboard Block Asynchronous View you need to set an ide=
ntifier
of the block. The asynchronous view fires the _fireLoa=
dDataEvent
method to get the data. The data must find itself in an a=
rray with the items
attribute.
In the example below an images
block is defined which looks=
up all content under the /images/
folder in the tree:
YUI.add('ezs-dashboardblockimagesview', function (Y) { 'use strict'; /** * Provides the Dashboard Images Block View class * * @module ez-dashboardblockimagesview */ Y.namespace('eZS'); var BLOCK_IDENTIFIER =3D 'images'; /** * The dashboard images block view * * @namespace eZS * @class DashboardBlockImagesView * @constructor * @extends eZ.DashboardBlockAsynchronousView */ Y.eZS.DashboardBlockImagesView =3D Y.Base.create('dashboardBlockImagesV= iew', Y.eZ.DashboardBlockAsynchronousView, [], { initializer: function () { this._set('identifier', BLOCK_IDENTIFIER); }, _fireLoadDataEvent: function () { this.fire('locationSearch', { viewName: 'images-dashboard', resultAttribute: 'items', loadContentType: true, loadContent: true, search: { criteria: {SubtreeCriterion: '/1/43/51/'}, limit: 10 } }); }, _getTemplateItem: function (item) { return { content: item.content.toJSON(), contentType: item.contentType.toJSON(), location: item.location.toJSON(), contentInfo: item.location.get('contentInfo').toJSON(), }; }, }); });=20
In the _getTemplateItem
method you can specify the structur=
e of the item which will be provided to the template. In the example above =
each item will be an object with four properties.
Now you have to create a template for the view, for example:
<h2 class=3D"ez-block-title">Images</h2> <div class=3D"ez-block-wrapper ez-asynchronousview"> {{#if loadingError}} <p class=3D"ez-asynchronousview-error ez-font-icon"> An error occurred while loading the images list. <button class=3D"ez-asynchronousview-retry ez-button ez-font-ico= n pure-button">Retry</button> </p> {{else}} <table class=3D"ez-block-items-table"> <thead class=3D"ez-block-header"> <tr> <th class=3D"ez-block-head-title">Title</th> <th class=3D"ez-block-head-content-type">Content Type= </th> <th class=3D"ez-block-head-version">Version</th>= ; <th class=3D"ez-block-head-modified">Last saved</t= h> </tr> </thead> <tbody class=3D"ez-block-content"> {{#each items}} <tr class=3D"ez-block-row"> <td class=3D"ez-block-cell">{{ contentInfo.name }}<= ;/td> <td class=3D"ez-block-cell">{{ lookup contentType.nam= es contentInfo.mainLanguageCode }}</td> <td class=3D"ez-block-cell">{{ contentInfo.currentVer= sionNo }}</td> <td class=3D"ez-block-cell ez-block-cell-options"> {{ contentInfo.lastModificationDate }} <div class=3D"ez-block-row-options"> <a class=3D"ez-block-option-edit ez-font-icon" h= ref=3D"{{ path "editContent" id=3DcontentInfo.id languageCode=3DcontentInfo= .mainLanguageCode }}"></a> <a class=3D"ez-block-option-view ez-font-icon" h= ref=3D"{{ path "viewLocation" id=3Dlocation.id languageCode=3DcontentInfo.m= ainLanguageCode }}"></a> </div> </td> </tr> {{/each}} </tbody> </table> {{/if}} </div>=20
loadingError
, because the asynchronous view provides it if the=
re are problems with loading data. If no error occurs, a table with basic i=
nfo about your images will be displayed.
The next step is adding the view and the template to the Dashboard. To d= o this, you need to create a plugin for the Dashboard view.
In the initializer you can use the public addBlock
method f=
rom the Dashboard view. In this method you only have to provide the instanc=
e of your view. Here you also set some properties for your new view: =
bubbleTargets
to make sure that the events will bubble up to the oth=
er views, and priority
where you can set the order of blocks i=
n the Dashboard (higher number goes first).
YUI.add('ezs-dashboardblocksplugin', function (Y) { 'use strict'; /** * The plugin is responsible for adding a new block to the dashboard. * * @module ezs-dashboardblocksplugin */ Y.namespace('eZS.Plugin'); Y.eZS.Plugin.DashboardBlocks =3D Y.Base.create('studioDashboardBlocks',= Y.Plugin.Base, [], { initializer: function () { this.get('host').addBlock(this.get('imagesBlockView')); } }, { NS: 'studioDashboardBlocks', ATTRS: { imagesBlockView: { valueFn : function () { return new Y.eZS.DashboardBlockImagesView({ bubbleTargets: this.get('host'), priority: 500 }); } } } }); Y.eZ.PluginRegistry.registerPlugin( Y.eZS.Plugin.DashboardBlocks, ['dashboardBlocksView'] ); });=20
If for whatever reason you want to remove a block, use another public me=
thod, removeBlock
, and provide it with just the block identifi=
er.
The last thing you have to do is add new modules to the yml configuratio= n:
ezs-dashboardblocksplugin: requires: - 'plugin' - 'base' - 'ez-pluginregistry' - 'ezs-dashboardblockimagesview' dependencyOf: ['ez-dashboardblocksview'] path: %ezstudioui.public_dir%/js/views/services/plugins/ezs-dashboardbl= ocksplugin.js ezs-dashboardblockimagesview: requires: - 'ez-dashboardblockasynchronousview' - 'dashboardblockimagesview-ez-template' path: %ezstudioui.public_dir%/js/views/ezs-dashboardblockimagesview.js dashboardblockimagesview-ez-template: type: 'template' path: %ezstudioui.public_dir%/templates/dashboardblock-images.hbt= =20
In this example the plugin is added as a dependency of the Dashboard blo= ck view, requiring the new images block view. The Dashboard images view in = turn requires the asynchronous view.
After this configuration is complete the Dashboard should display the ne= w block.
V1.4=
A Content item can be treated as an instance of a Content Type. The type= of a Content item is very important information to provide to the user. Th= e Content Type to which a Content item belongs is represented graphically u= sing an icon near the Content item name. Essentially, the Content Types are= project-specific so the icons can be easily configured and extended by int= egrators.
Icons in the PlatformUI interface are provided by an icon font. For Cont= ent Types, the idea is to expand that concept so that while generating the = interface, we end up with a code similar to:
<h1 class=3D"ez-contenttype-icon ez-contenttype-icon-folde= r">Folder Name</h1>=20
With such classes, the h1
is specified to display a Content=
Type icon. The class ez-contenttype-icon
makes sure the eleme=
nt is styled for that and gets the default Content Type icon. The second cl=
ass is specific to the Content Type based on its identifier and if it's def=
ined in one of the CSS files, the element will get the custom Content Type =
icon defined there.
The extensibility of Content Type icons is tackled differently depending=
on the use case, but it relies on the ability to embed a custom CSS file i=
n PlatformUI with css.yml
.
To prevent the need to configure/extend the system, we provide several p= re-configured icons for very common Content Types such as:
product
author
category
gallery
/ portfolio
blog_post
/ blogpost
/ post
blog
/ weblog
news
pdf
document
photo
comment
wiki
wiki_page
/ wikipage
There are three ways of choosing Content Type icons:
In such a case you need to pick the icon code. For that, the icomoon a= pplication can be used until the UI guidelines are up-to-date and refer= ence the available icons. To ease that process and the readability of the c= ode, we'll use ligatures in the font icon so that the CSS code for a custom= Content Type could look like:
/* in a custom CSS file included with `css.yml` */ .ez-contenttype-icon-mycontenttypeidentifier:before { content: "product"; /* because this icon matches the usage of such cont= ent items */ }=20
If the icons we provide do not fit a custom Content Type, then a new cus=
tom icon font has to be added. To generate the icon, the Icomoon App can be=
used (or any other tool). Then, using a custom CSS stylesheet, this font c=
an be included and the ez-contenttype-icon-<content type identifie=
r>
can be configured to use that font.
Example:
/* in a custom CSS file included with `css.yml` */ @font-face { font-family: 'my-icon-font'; src:url('../../fonts/my-icon-font.eot'); src:url('../../fonts/my-icon-font.eot?#iefix') format('embedded-opentyp= e'), url('../../fonts/my-icon-font.woff') format('woff'), url('../../fonts/my-icon-font.ttf') format('truetype'), url('../../fonts/my-icon-font.svg#my-icon-font') format('svg'); font-weight: normal; font-style: normal; } .ez-contenttype-icon-myidentifier:before { font-family: 'my-icon-font'; content: "myiconcode"; } /* repeated as many times as needed for each custom Content Type */= =20
The solution for this use case is very close to the previous one. A cust=
om icon font will have to be produced, loaded with a custom CSS file, and t=
hen the ez-contenttype-icon
style has to be changed to use tha=
t new font.
Example:
/* in a custom CSS file included with `css.yml` */ @font-face { font-family: 'my-icon-font'; src:url('../../fonts/my-icon-font.eot'); src:url('../../fonts/my-icon-font.eot?#iefix') format('embedded-opentyp= e'), url('../../fonts/my-icon-font.woff') format('woff'), url('../../fonts/my-icon-font.ttf') format('truetype'), url('../../fonts/my-icon-font.svg#my-icon-font') format('svg'); font-weight: normal; font-style: normal; } .ez-contenttype-icon:before { font-family: 'my-icon-font'; /* replaces ez-platformui-icomoon */ /* no further change needed if the custom icon font uses the same * codes/ligatures */ }=20
Custom Javascript can be added to PlatformUI using the following configu= ration block:
ez_platformui: system: default: javascript: files: - '<path to js file>'=20
V1.7=
EZ ENTERPRI= SE
Form Builder Bundle currently comes with three basic types of fields: Si= ngle Line Text, Paragraph Text and Email.
It was designed to be easy to extend by adding new types of fields.
Default field definitions are available in Resources\config\defaul=
t_fields.yml
.
Field definitions are contained under the fields
key. Each =
definition has its own key, e.g. single_line_text
. Each defini=
tion must contain two sections:
identifier
- name of the definition used on the front end<=
/li>
displayName
- name displayed in the Page mode editor in th=
e fields
tabThe definition can also contain the following optional sections:
validators
- defines validators that the field will use. T=
his must contain the validator's identifier and the values that will be che=
cked during validation, for example:validators: - { identifier: required, value: 1 }=20
attributes
- contains the field's attributes. You can plac=
e here custom attributes for new fields, like in https://=
github.com/ezsystems/ezstudio-form-builder/blob/master/bundle/Resources/con=
fig/default_fields.yml#L33. There are also four default a=
ttributes that are used for every field: LABEL_NAME
, LABEL_HELP_TEXT
, LABEL_ADMIN_LABEL and LABEL_PLACEHOLDE=
R_TEXT
. If you wish, you can override them in your con=
figuration.
views
- provides a list of views that will be used to disp=
lay the field. At least one view must be defined, with the keys name<=
/code>, thumbnail
and template
, for example:
views: basic: name: Form Test Line Text Basic thumbnail: /bundles/ezsystemsformbuilder/images/thumbnails/= single_line_text/basic.svg template: EzSystemsFormBuilderBundle:fields:single_line_tex= t/basic.html.twig=20
This procedure assumes you are creating a separate Bundle to house your = new type of form field.
Create a YAML configuration file, e.g. Resources\config\extended_f=
ields.yml
, with the following code:
fields: test_text: identifier: testLineText displayName: 'Test Line Text' validators: - { identifier: required, value: 1 } attributes: name: 'test line attribute' views: basic: name: Form Test Line Text Basic thumbnail: /bundles/ezsystemsformbuilder/images/thumbnails/= single_line_text/basic.svg template: EzSystemsFormBuilderBundle:fields:single_line_tex= t/basic.html.twig=20
When creating a new template for the field definition, remember to add m=
andatory ezform-field
class and field.id<=
/code> as shown below:
{% extends 'EzSystemsFormBuilderBundle:fields:field.html.twig' %} {% block input %} <input type=3D"text" class=3D"ezform-field ..." id=3D"{{ field.id }}= " placeholder=3D"{{ field.placeholderText }}"> {% endblock %}=20
DependencyInjection\TestExtension.php
=
classThe class must implement the PrependExtensionInterface
inte=
rface:
class TestExtension implements PrependExtensionInterface=20
In the prepend
method in TestExtension.php
add the following lines at the end:
public function prepend(ContainerBuilder $container) { ... $configFile =3D __DIR__ . '/../Resources/config/extended_fields.yml= '; $config =3D Yaml::parse(file_get_contents($configFile)); $container->loadFromExtension('ez_systems_form_builder', $config= ); $container->addResource(new FileResource($configFile)); =20 }=20
You can create your own validators by reproducing the following configur= ation:
A validator implements the EzSystems\FormBuilder\SPI\ValidatorInte=
rface.php
interface and extends the abstract class EzSystems\F=
ormBuilder\Core\Validator\Validator.php
.
The interface requires the implementation of the following methods:
validate
getLabel
getErrorMessage
setLimitation
getValueType
The validate
method is the one that contains the logic=
for the validation. It returns true
when validation is succes=
sful, or false
when the data does not validate:
/** * @return bool */ public function validate($value);=20
The getLabel
method returns a string with the name of =
the validator that will be used in the editor:
/** * @return string */ public function getLabel();=20
The getErrorMessage
method returns error message(s) to=
appear when the validate
method returns false
:=
p>
/** * @return array */ public function getErrorMessage();=20
The setLimitation
method allows the configuration of l=
imitations. Its default implementation is contained in the Validator<=
/code> abstract class:
/** * @param mixed $limitation */ public function setLimitation($limitation);=20
The getValueType
method returns the name of the checke=
d value type:
/** * @return string */ public function getValueType();=20
Currently the abstract class Validator
has three value type=
s (defined in Core\Validator\Validator.php
):
const TYPE_INTEGER =3D 'integer'; const TYPE_STRING =3D 'string'; const TYPE_BOOL =3D 'bool';=20
The validator must be tagged as form_builder.field_validator
. Due to this the Resources\config\validator_services.yml
fil=
e contains two entries, one in the parameters
section:
form_builder.validator.example.class: EzSystems\FormBuilder\Core\Va= lidator\ExampleValidator=20
and one in the services
section:
form_builder.validator.example: class: '%form_builder.validator.example.class%' tags: - { name: form_builder.field_validator, alias: example }= =20
Whenever a form is submitted and stored in a database, lib\Core\Si=
gnalSlot\Signal\FormSubmit
emits signal in a submitF=
orm
service. You can create your own listeners, called Signal s=
lots, to capture the FormSubmit signal.
Below you can find an example of a custom Signal slot. It saves submissi= on to a text file.
<?php namespace AppBundle\SignalSlot; use Symfony\Component\Filesystem\Filesystem; use eZ\Publish\Core\SignalSlot\Slot; use eZ\Publish\Core\SignalSlot\Signal; class HandleSubmission extends Slot { /** * Receive the given $signal and react on it. * * @param EzSystems\FormBuilder\Core\SignalSlot\Signal\FormSubmit $sign= al */ public function receive(Signal $signal) { $fs =3D new Filesystem(); $formId =3D $signal->formId; $submission =3D $signal->submission; $created =3D $submission->created->format("Y-m-d.H:i:s"); $dataRows =3D []; foreach ($submission->fields as $field) { $dataRows[] =3D "{$field->label}: {$field->value}"; } $fs->mkdir("forms/{$formId}"); $fs->dumpFile("forms/{$formId}/{$created}.txt", implode("\n", $d= ataRows)); } }=20
It has to be registered as a tagged Symfony service, like this:
app_bundle.handle_submission: class: "AppBundle\SignalSlot\HandleSubmission" tags: - { name: ezpublish.api.slot, signal: '\EzSystems\FormBuilder\C= ore\SignalSlot\Signal\FormSubmit' }=20
V1.8=
Form Builder fields introduced in v1.8 require additional configuration.=
To make use of the Date field you need to add the necessary assets. The = assets should be added in page head with the following code:
{% javascripts ... 'bundles/ezsystemsformbuilder/js/vendors/*/*.js' %} <script type=3D"text/javascript" src=3D"{{ asset_url }}"></scr= ipt> {% endjavascripts %}=20
{% stylesheets filter=3D'cssrewrite' ... 'bundles/ezsystemsformbuilder/css/vendors/*/*.css' %} <link rel=3D"stylesheet" type=3D"text/css" href=3D"{{ asset_url }}"&= gt; {% endstylesheets %}=20
If you wish to add a new date format, the alias
in the date=
field config must follow this pattern:
d
or D
- day of the month (1-2 digits)
DD
- day of the month (2 digits)
m=
code> or
M
- month of the year (1-2 digits)
mm
or MM
- month (2 digits)
yy
or YY
yyyy
or YYYY
- year (4 =
digits)
for example:
d-m-yyyy
- 16-1-2017
mm/dd/yy
- 01/16/17