Neos 2.3 Documentation

Neos is a free enterprise web content management system licensed under the GPL.

This version of the documentation covering Neos 2.3.3 has been rendered at: Jun 16, 2019

Getting Started

Feature List

Note

The following list contains the key technical features of Neos. If you want to learn about the great features and experience that neos offers to editors and visitors please have a look at the Neos Website.

ContentRepository and ContentElements

The content repository is the conceptual core of Neos. It can store arbitrary content by managing so called Nodes that can have custom properties and child nodes. The list of available NodeTypes is extensible and hierarchical so new NodeTypes can be created by extending the existing ones.

Neos already comes with a sophisticated list of ContentElements to cover the basic editing needs without further extension. The Standard ContentElements are implemented as NodeTypes from the Package TYPO3.Neos.NodeTypes and contain the elements Headline, Text, Image, Image with Text, 2- 3- 4-Columns, Download List, Forms and Menu.

The List of ContentElements is easily extensible and the demo site already contains examples for YouTube and Flickr Integration and even a Custom Image Slider.

Note

To lean about the Structure and Extensibility of the ContentRepository have a look at the Sections Content Structure and the Property Editor Reference.

Inline- and Structural Editing

Neos offers inline editing for basically all data that is visible on the website and fully supports the navigation of the website menus during editing. For metadata or mode abstract informations it has an extensible Inspector. By implementing a custom edit/preview mode the editing in Neos can be extended even further.

Note

To get an understanding of the editing workflow we recommend the section User Interface Basics.

Content Dimensions and Languages

Most content has to be managed in variants for different languages or target groups. For that neos offers the concept so called content dimensions.

Note

The configuration of ContentDimensions is explained in the section Content Dimensions.

Workspaces and Publishing

Neos has workspaces built in. Every user works in his personal workspace and can publish his changes to make them public. Furthermore, there is a “Workspace” module which can be used for publishing individual nodes.

Note

The concept of workspaces will be extended in future releases so shared editing workspaces between users and publishing to non-live workspaces will become possible.

Import Export

Neos has full support for importing and exporting site content using content stored in XML files. That can also be used to regularly import external data into Neos or to migrate content from other systems.

Note

The reference of the import and export command can be found in the Neos Command Reference.

Multi Domain Support

Using the command line tools or the site-management backend module it’s possible to link a hostname to a site node, making it possible to have a multi domain installation in Neos. This way you can for example create a multilingual website using a ‘multi-tree concept’.

Note

There are still a few bugs related to URI resolving in this area; it needs to be more thoroughly tested.

Robust and secure Foundation

Being built upon the most advanced PHP framework to date – Flow – makes your websites ready for whatever the future holds for you.

Flow is secure by default, keeping your developers focussed on their main task - building your application - without having to worry about low level implementations.

Surf Deployment and Cloud Support

The developers of Neos also created “Surf” a professional tool for downtime free server-deployment that is optimized for Neos. With Surf Neos can be easily deployed to all kinds of hosting environments being it dedicated servers, virtual-machines or cloud solutions of different flavours. The media handling of Neos is “cloud ready” by design and can handle external resources exceptionally well.

Installation

Tip

Neos is built on top of the Flow framework. If you run into technical problems, keep in mind to check the Flow documentation for possible hints as well.

Requirements

Neos has at least the same system requirements as Flow. You can find them in the Flow Requirements Documentation.

The most important requirements are:

  • A Webserver (Apache and Nginx are preferred but others work as well)
  • A Database (MySQL and MariaDB are preferred but any Database supported by Doctrine DBAL should work).
  • PHP >= 5.5.0 (make sure the PHP CLI has the same version)
    • PHP modules mbstring, tokenizer and pdo_mysql
    • PHP functions system(), shell_exec(), escapeshellcmd() and escapeshellarg()
    • It is recommended to install one of the PHP modules imagick or gmagick

Fundamental Installation

  1. First you need to install the dependency manager Composer (if you don’t have it already):

    curl -sS https://getcomposer.org/installer | php
    

    By issuing this command Composer will get downloaded as composer.phar to your working directory. If you like to have composer installed globally, you can simply move it to a directory within your $PATH environment.

    mv composer.phar /usr/local/bin/composer
    

    Note

    If you are on Windows please refer to the offical documentation on how to install Composer on Windows

  2. Go to your htdocs directory and create a new project based on the Neos base distribution:

    cd /your/htdocs/
    php /path/to/composer.phar create-project neos/neos-base-distribution Neos
    

    Composer will take care of downloading all dependencies for running your Neos installation to the directory Neos. You can safely delete the vcs files by answering ‘Y’ to the question ‘Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]?’.

  3. Next set up a virtual host inside your Apache configuration. Set the DocumentRoot to the Web directory inside the Neos installation.

    NameVirtualHost *:80 # if needed
    
    <VirtualHost *:80>
       DocumentRoot "/your/htdocs/Neos/Web/"
       # enable the following line for production context
       #SetEnv FLOW_CONTEXT Production
       ServerName neos.demo
    </VirtualHost>
    

    Make sure that the mod_rewrite module is loaded and restart apache. For further information on how to set up a virtual host with apache please refer to the Apache Virtual Host documentation.

  4. Add an entry to /etc/hosts to make your virtual host reachable:

    127.0.0.1 neos.demo
    

    Make sure to use the same name you defined in ServerName in the virtual host configuration above.

  5. Set file permissions as needed so that the installation is read- and writeable by the webserver’s user and group:

    sudo ./flow core:setfilepermissions john www-data www-data
    

    Replace john with your current username and www-data with the webserver’s user and group.

    For detailed instructions on setting the needed permissions see Flow File Permissions

    Note

    Setting file permissions is not necessary and not possible on Windows machines. For Apache to be able to create symlinks, you need to use Windows Vista (or newer) and Apache needs to be started with Administrator privileges.

  6. Now go to http://neos.demo/setup and follow the on-screen instructions.

The Neos Setup Tool

  1. A check for the basic requirements of Flow and Neos will be run. If all is well, you will see a login screen. If a check failed, hints on solving the issue will be shown and you should fix what needs to be fixed. Then just reload the page, until all requirements are met.

  2. The login screen will tell you the location of a file with a generated password. Keep that password in some secure place, the generated file will be removed upon login! It is possible to have a new password rendered if you lost it, so don’t worry too much.

    Neos login page
  3. Fill in the database credentials in the first step. The selector box will be updated with accessible databases to choose from, or you can create a new one.

    Tip

    Configure your MySQL server to use the utf8_unicode_ci collation by default if possible!

    Setup database credentials
  4. In the next step a user with administrator privileges for editing with Neos is created.

    Create admin user
  5. The following step allows you to import an existing site or kickstart a new site. To import the demo site, just make sure it is selected in the selector box and go to the next step.

    To kickstart a new site, enter a package and site name in the form before going to the next step.

    If you are new to Neos, we recommend to import the existing demo site so you can follow the next section giving you a basic tour of the user interface.

    Create new site or import an existing
  6. If all went well you’ll get a confirmation the setup is completed, and you can enter the frontend or backend of your Neos website.

    Warning

    If you install the Neos demo site and it is publicly accessible, make sure the “Try me” page in the page tree is not publicly accessible because it has a form allowing you to create backend editor accounts with rights to edit website content.)

    The Neos start page

    The Neos demo site start page

Technical Principles

User Guide

This is the end-user documentation covering the structure of the backend and the modules there, as well as some basic principles and usage instructions.

User Interface Basics

Neos User Interface
  1. Toggle button for the Menu
  2. The Navigate component
  3. The Edit/Preview Panel
  4. The Page tree
  5. Publish button(s)
  6. The Property Inspector
  7. The Structure tree
  8. The content canvas
  9. Discard / Apply changes

Toggle button for the Menu

Show or hide the Module Menu using this button.

The Navigate component

Using the Navigate component you can conveniently find your way through your contents. See ‘The Page tree’.

The Edit/Preview Panel

The Edit/Preview Panel gives you the possibility to switch between the (default) ‘In Place’ editing mode to and from the ‘Raw Content’ editing mode.

It also contains the Preview section where you can choose between customizable presentation modes, i.e. a print style and a default Desktop style.

The Page tree

The Page tree is filterable and searchable and can be edited inline.

Publish button(s)

These publication buttons aggregate your changes which you can publish at your chosen time. See Workspaces for more information on the use of workspaces.

The Property Inspector

The Property Inspector gives you detailed property editing options for the chosen nodetype, whether this be a page or a content element.

The Structure tree

The Structure tree is a nodetype tree which gives you detailed information of how your content is structured. It gives you information about which type, its position and its nesting level. This can also be used to navigate the content of a page.

The content canvas

The content canvas is where you can add/edit your content.

Discard / Apply changes

Neos saves your changes on the fly as much as possible. When editing properties you must apply or discard the changes you made.

Workspaces

All content in Neos lives in Workspaces. The publicly visible content comes from a workspace called live, and any editing takes place in other workspaces. Edits will only become visible on the live website if they are published to the live workspace.

That means workspaces can be seen as a way to group content based on it’s state in the editing process. Workspaces behave like transparent sheets of paper: On your own sheet you can draw new things, but the live sheet below is still visible (and due to it’s magic nature even updates of other editors publish changes to it).

Workspaces can also be stacked: between the live workspace and an editor’s own workspace can be yet another workspace that is shared between editors to allow collaboration on bigger changes as well as the review of changes before they are published. The workspace a workspace is based on is called base workspace.

Terminology

Public Workspace
A public workspace has no owner and is not based on another workspace. Usually there is one public workspace name live: it contains the content that is visible to the visitors of a Neos-driven website.
Internal Workspace
An internal workspace has no specific owner and is shared between editors. Internal workspaces are used to collaborate on bigger changes, like preparing a sales campaign.
Private Workspace
Private workspaces are owned by a specific editor and only visible to that editor (and those having the administrator role). They can be used to shelve work temporarily, for example.
Personal Workspace
Every editor has exactly one personal workspace. Any editing goes to that workspace first, no matter what. This personal workspace is only accessible by its owner.

Managing Workspaces

From the user side workspace management is rather simple. New workspaces can be created in the Workspaces module. As soon as more than one workspace is available, a new option will appear in the publish button of the content module. It allows to switch the workspace that is being worked on (in more technical terms it will re-base the personal workspace onto the selected one) and that will be published to.

Note

To be able to switch the base workspace, there must be no pending changes in the personal workspace.

In the Workspaces module a list of existing workspaces is shown. That list shows the base workspace and owner as well as a quick statistics view of the unpublished changes in each workspace. Depending on permissions buttons allow to review changes, edit a workspace or delete it.

When changes in a workspace are reviewed, a list of those changes is shown and they can be published or discarded completely or selectively.

Permissions

Out-of-the-box

  • all users can create new private workspaces.
  • all users can edit/delete their own private workspaces.
  • users with the TYPO3.Neos:RestrictedEditor role can only publish to internal or private workspaces.
  • other users (having the TYPO3.Neos:Editor role) can also publish to the public workspace live and create new internal workspaces.
  • Administrators (having the TYPO3.Neos:Administrator role) can create internal workspaces and manage (edit and delete) internal as well as private workspaces.

Workflow Examples

Doing some quick edits

Publish to live directly

This is a very quick and easy workflow for editors that may publish to the live workspace. Just do any edits in your personal workspace and publish to live when you are done.

Using a review workspace

If publishing to live is not allowed or a review of the changes is desired, an internal or private workspace can be created. The changes are published to that workspace first and can then be reviewed and published to live by a reviewer or administrator.

Prepare a new section

If a new section for the website is to be prepared collaboratively, a new internal workspace needs to be created. Everyone working on the new section switches their personal workspace to use the internal workspace as base workspace and published changes to it. As soon as everything is done the changes can be reviewed and published.

If some edits need to be made to other parts of the website in between, the personal workspace base can be switched to the live or another workspace as needed. This allows to do independent edits without conflicts.

Creating a Site with Neos

This guide explains how to implement websites with Neos. It specifically covers the structuring of content using the TYPO3 Content Repository (TYPO3CR), and how the content is rendered using TypoScript and Fluid.

Node Types

These are the development guidelines of Neos.

Content Structure

Before we can understand how content is rendered, we have to see how it is structured and organized. These basics are explained in this section.

Nodes inside the TYPO3 Content Repository

The content in Neos is not stored inside tables of a relational database, but inside a tree-based structure: the so-called TYPO3 Content Repository.

To a certain extent, it is comparable to files in a file-system: They are also structured as a tree, and are identified uniquely by the complete path towards the file.

Note

Internally, the TYPO3CR currently stores the nodes inside database tables as well, but you do not need to worry about that as you’ll never deal with the database directly. This high-level abstraction helps to decouple the data modelling layer from the data persistence layer.

Each element in this tree is called a Node, and is structured as follows:

  • It has a node name which identifies the node, in the same way as a file or folder name identifies an element in your local file system.
  • It has a node type which determines which properties a node has. Think of it as the type of a file in your file system.
  • Furthermore, it has properties which store the actual data of the node. The node type determines which properties exist for a node. As an example, a Text node might have a headline and a text property.
  • Of course, nodes may have sub nodes underneath them.

If we imagine a classical website with a hierarchical menu structure, then each of the pages is represented by a TYPO3CR Node of type Document. However, not only the pages themselves are represented as tree: Imagine a page has two columns, with different content elements inside each of them. The columns are stored as Nodes of type ContentCollection, and they contain nodes of type Text, Image, or whatever structure is needed. This nesting can be done indefinitely: Inside a ContentCollection, there could be another three-column element which again contains ContentCollection elements with arbitrary content inside.

Comparison to TYPO3 CMS

In TYPO3 CMS, the page tree is the central data structure, and the content of a page is stored in a more-or-less flat manner in a separate database table.

Because this was too limited for complex content, TemplaVoila was invented. It allows to create an arbitrary nesting of content elements, but is still plugged into the classical table-based architecture.

Basically, Neos generalizes the tree-based concept found in TYPO3 CMS and TemplaVoila and implements it in a consistent manner, where we do not have to distinguish between pages and other content.

Predefined Node Types

Neos is shipped with a number of predefined node types. It is helpful to know some of them, as they can be useful elements to extend, and Neos depends on some of them for proper behavior.

There are a few core node types which are needed by Neos; these are shipped in TYPO3.Neos directly. All other node types such as Text, Image, … are shipped inside the TYPO3.Neos.NodeTypes package.

TYPO3.Neos:Node

TYPO3.Neos:Node is a (more or less internal) base type which should be extended by all content types which are used in the context of Neos.

It does not define any properties.

TYPO3.Neos:Document

An important distinction is between nodes which look and behave like pages and “normal content” such as text, which is rendered inside a page. Nodes which behave like pages are called Document Nodes in Neos. This means they have a unique, externally visible URL by which they can be rendered.

The standard page in Neos is implemented by TYPO3.Neos.NodeTypes:Page which directly extends from TYPO3.Neos:Document.

TYPO3.Neos:ContentCollection and TYPO3.Neos:Content

All content which does not behave like pages, but which lives inside them, is implemented by two different node types:

First, there is the TYPO3.Neos:ContentCollection type: A TYPO3.Neos:ContentCollection has a structural purpose. It usually contains an ordered list of child nodes which are rendered inside.

TYPO3.Neos:ContentCollection may be extended by custom types.

Second, the node type for all standard elements (such as text, image, youtube, …) is TYPO3.Neos:Content. This is–by far–the most often extended node type.

Extending the NodeTypes

To extend the existing NodeTypes or to create new ones please read at the Node Type Definition reference.

Node Type Definition

Each TYPO3CR Node (we’ll just call it Node in the remaining text) has a specific node type. Node Types can be defined in any package by declaring them in Configuration/NodeTypes.yaml.

Each node type can have one or multiple parent types. If these are specified, all properties and settings of the parent types are inherited.

A node type definition can look as follows:

'My.Package:SpecialHeadline':
  superTypes:
    'TYPO3.Neos:Content': true
  ui:
    label: 'Special Headline'
    group: 'general'
  properties:
    headline:
      type: 'string'
      defaultValue: 'My Headline Default'
      ui:
        inlineEditable: true
      validation:
        'TYPO3.Neos/Validation/StringLengthValidator':
          minimum: 1
          maximum: 255

The following options are allowed:

abstract

A boolean flag, marking a node type as abstract. Abstract node types can never be used standalone, they will never be offered for insertion to the user in the UI, for example.

Abstract node types are useful when using inheritance and composition, so mark base node types and mixins as abstract.

aggregate

A boolean flag, marking a node type as aggregate. If a node type is marked as aggregate, it means that:

  • the node type can “live on its own”, i.e. can be part of an external URL
  • when moving this node, all node variants are also moved (across all dimensions)
  • Recursive copying only happens inside this aggregate, and stops at nested aggregates.

The most prominent aggregate is TYPO3.Neos:Document and everything which inherits from it, like TYPO3.Neos.NodeTypes:Page.

superTypes

An array of parent node types as keys with a boolean value:

'TYPO3.Neos:Document':
  superTypes:
    'Acme.Demo.ExtraMixin': true

'TYPO3.Neos:Shortcut':
  superTypes:
    'Acme.Demo.ExtraMixin': false
constraints

Constraint definitions stating which nested child node types are allowed. Also see the dedicated chapter Node Type Constraints for detailed explanation:

constraints:
  nodeTypes:
    # ALLOW text, DISALLOW Image
    'TYPO3.Neos.NodeTypes:Text': true
    'TYPO3.Neos.NodeTypes:Image': false
    # DISALLOW as Fallback (for not-explicitly-listed node types)
    '*': false
childNodes

A list of child nodes that are automatically created if a node of this type is created. For each child the type has to be given. Additionally, for each of these child nodes, the constraints can be specified to override the “global” constraints per type. Here is an example:

childNodes:
  someChild:
    type: 'TYPO3.Neos:ContentCollection'
    constraints:
      nodeTypes:
        # only allow images in this ContentCollection
        'TYPO3.Neos.NodeTypes:Image': true
        '*': false

By using position, it is possible to define the order in which child nodes appear in the structure tree. An example may look like:

'TYPO3.Neos.NodeTypes:Page':
  childNodes:
    'someChild':
      type: 'TYPO3.Neos:ContentCollection'
      position: 'before main'

This adds a new ContentCollection called someChild to the default page. It will be positioned before the main ContentCollection that the default page has. The position setting follows the same sorting logic used in TypoScript (see the TypoScript Reference).

label

When displaying a node inside the Neos UI (e.g. tree view, link editor, workspace module) the label option will be used to generate a human readable text for a specific node instance (in contrast to the ui.label which is used for all nodes of that type).

The label option accepts an Eel expression that has access to the current node using the node context variable. It is recommended to customize the label option for node types that do not yield a sufficient description using the default configuration.

Example:

'Neos.Demo:Flickr':
  label: ${'Flickr plugin (' + q(node).property('tags') + ')'}
generatorClass
Alternatively the class of a node label generator implementing TYPO3\TYPO3CR\Domain\Model\NodeLabelGeneratorInterface can be specified as a nested option.
ui

Configuration options related to the user interface representation of the node type

label
The human-readable label of the node type
group

Name of the group this content element is grouped into for the ‘New Content Element’ dialog. It can only be created through the user interface if group is defined and it is valid.

All valid groups are given in the TYPO3.Neos.nodeTypes.groups setting

position
Position inside the group this content element is grouped into for the ‘New Content Element’ dialog. Small numbers are sorted on top.
icon

This setting defines the icon that the Neos UI will use to display the node type.

Currently it is only possible to use a predefined selection of icons, which are available in Font Awesome http://fortawesome.github.io/Font-Awesome/3.2.1/icons/.

help

Configuration of contextual help. Displays a message that is rendered as popover when the user clicks the help icon in an insert node dialog.

message
Help text for the node type. It supports markdown to format the help text and can be translated (see Translate NodeTypes).
thumbnail

This is shown in the popover and can be supplied in two ways:

  • as an absolute URL to an image (http://static/acme.com/thumbnails/bar.png)
  • as a resource URI (resource://AcmeCom.Website/NodeTypes/Thumbnails/foo.png)
If the thumbnail setting is undefined but an image matching the nodetype name

is found, it will be used automatically. It will be looked for in <packageKey>/Resources/Public/NodeTypes/Thumbnails/<nodeTypeName>.png with packageKey and nodeTypeName being extracted from the full nodetype name like this:

AcmeCom.Website:FooWithBar -> AcmeCom.Website and FooWithBar

The image will be downscaled to a width of 342 pixels, so it should either be that size to be placed above any further help text (if supplied) or be half that size for the help text to flow around it.

inlineEditable
If true, it is possible to interact with this Node directly in the content view. If false, an overlay is shown preventing any interaction with the node. If not given, checks if any property is marked as ui.inlineEditable.
inspector

These settings configure the inspector in the Neos UI for the node type

tabs

Defines an inspector tab that can be used to group property groups of the node type

label
The human-readable label for this inspector tab
position
Position of the inspector tab, small numbers are sorted on top
icon

This setting define the icon to use in the Neos UI for the tab

Currently it’s only possible to use a predefined selection of icons, which are available in Font Awesome http://fortawesome.github.io/Font-Awesome/3.2.1/icons/.

groups

Defines an inspector group that can be used to group properties of the node type

label
The human-readable label for this inspector group
position
Position of the inspector group, small numbers are sorted on top
icon
This setting define the icon to use in the Neos UI for the group
tab
The tab the group belongs to. If left empty the group is added to the default tab.
collapsed
If the group should be collapsed by default (true or false). If left empty, the group will be expanded.
properties

A list of named properties for this node type. For each property the following settings are available.

Note

Your own property names should never start with an underscore _ as that is used for internal properties or as an internal prefix.

type
Data type of this property. This may be a simple type (like in PHP), a fully qualified PHP class name, or one of these three special types: DateTime, references, or reference. Use DateTime to store dates / time as a DateTime object. Use reference and references to store references that point to other nodes. reference only accepts a single node or node identifier, while references accepts an array of nodes or node identifiers.
defaultValue
Default value of this property. Used at node creation time. Type must match specified ‘type’.
ui

Configuration options related to the user interface representation of the property

label
The human-readable label of the property
help

Configuration of contextual help. Displays a message that is rendered as popover when the user clicks the help icon in the inspector.

message
Help text for this property. It supports markdown to format the help text and can be translated (see Translate NodeTypes).
reloadIfChanged
If true, the whole content element needs to be re-rendered on the server side if the value changes. This only works for properties which are displayed inside the property inspector, i.e. for properties which have a group set.
reloadPageIfChanged
If true, the whole page needs to be re-rendered on the server side if the value changes. This only works for properties which are displayed inside the property inspector, i.e. for properties which have a group set.
inlineEditable
If true, this property is inline editable, i.e. edited directly on the page through Aloha.
aloha

This section controls the text formatting options the user has available for this property. Example:

aloha:
  'format': # Enable specific formatting options.
    'strong': true
    'b': false
    'em': true
    'i': false
    'u': true
    'sub': true
    'sup': true
    'p': true
    'h1': true
    'h2': true
    'h3': true
    'h4': false
    'h5': false
    'h6': false
    'code': false
    'removeFormat': true
  'table':
    'table': true
  'link':
    'a': true
  'list':
    'ul': true
    'ol': true
  'alignment':
    'left': true
    'center': true
    'right': true
    'justify': true
  'formatlesspaste':
    # Show toggle button for formatless pasting.
    'button': true
    # Whether the formatless pasting should be enable by default.
    'formatlessPasteOption': false
    # If not set the default setting is used: 'a', 'abbr', 'b', 'bdi', 'bdo', 'cite', 'code', 'del', 'dfn',
    # 'em', 'i', 'ins', 'kbd', 'mark', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'small', 'strong', 'sub', 'sup',
    # 'time', 'u', 'var'
    'strippedElements': ['a']
  'autoparagraph': true # Automatically wrap non-wrapped text blocks in paragraph blocks.

Example of disabling all formatting options:

aloha:
  'format': []
  'table': []
  'link': []
  'list': []
  'alignment': []
  'formatlesspaste':
    'button': false
    'formatlessPasteOption': true
inspector

These settings configure the inspector in the Neos UI for the property.

group

Identifier of the inspector group this property is categorized into in the content editing user interface. If none is given, the property is not editable through the property inspector of the user interface.

The value here must reference a groups configured in the ui.inspector.groups element of the node type this property belongs to.

position
Position inside the inspector group, small numbers are sorted on top.
editor
Name of the JavaScript Editor Class which is instantiated to edit this element in the inspector.
editorOptions
A set of options for the given editor, see the Property Editor Reference.
editorListeners
Allows to observe changes of other properties in order to react to them. For details see Depending Properties
validation
A list of validators to use on the property. Below each validator type any options for the validator can be given. See below for more information.

Tip

Unset a property by setting the property configuration to null (~).

Here is one of the standard Neos node types (slightly shortened):

'TYPO3.Neos.NodeTypes:Image':
  superTypes:
    'TYPO3.Neos:Content': true
  ui:
    label: 'Image'
    icon: 'icon-picture'
    inspector:
      groups:
        image:
          label: 'Image'
          icon: 'icon-image'
          position: 5
  properties:
    image:
      type: TYPO3\Media\Domain\Model\ImageInterface
      ui:
        label: 'Image'
        reloadIfChanged: true
        inspector:
          group: 'image'
    alignment:
      type: string
      defaultValue: ''
      ui:
        label: 'Alignment'
        reloadIfChanged: true
        inspector:
          group: 'image'
          editor: 'TYPO3.Neos/Inspector/Editors/SelectBoxEditor'
          editorOptions:
            placeholder: 'Default'
            values:
              '':
                label: ''
              center:
                label: 'Center'
              left:
                label: 'Left'
              right:
                label: 'Right'
    alternativeText:
      type: string
      ui:
        label: 'Alternative text'
        reloadIfChanged: true
        inspector:
          group: 'image'
      validation:
        'TYPO3.Neos/Validation/StringLengthValidator':
          minimum: 1
          maximum: 255
    hasCaption:
      type: boolean
      ui:
        label: 'Enable caption'
        reloadIfChanged: true
        inspector:
          group: 'image'
    caption:
      type: string
      defaultValue: '<p>Enter caption here</p>'
      ui:
        inlineEditable: true

Node Type Constraints

In a typical Neos project, you will create lots of custom node types. However, many node types should only be used in a specific context and not everywhere.

For instance, inside the “Chapter” node type of the Neos Demo Site (which is a document node), one should only be able to create nested chapters, and not pages or shortcuts. Using node type constraints, this can be enforced:

'Neos.Demo:Chapter':
  constraints:
    nodeTypes:
      'Neos.Demo:Chapter': true
      '*': false

In the above example, we disable all node types using *: false, and then enable the Chapter node type as well as any node type that super types it. The closest matching constraint of a super type is used to determine the constraint.

You might now wonder why it is still possible to create content inside the chapter (because everything except Chapter is disabled with the above configuration): The reason is that node type constraints are only enforced for nodes which are not auto-created. Because “Chapter” has an auto-created main ContentCollection, it is still possible to add content inside. In the following example, we see the NodeType definition which is shipped with the demo website:

'Neos.Demo:Chapter':
  superTypes:
    'TYPO3.Neos:Document': true
  childNodes:
    'main':
      type: 'TYPO3.Neos:ContentCollection'

Now, it might additionally be useful to only allow text and images inside the chapter contents. This is possible using additional constraints for each auto-created child node:

'Neos.Demo:Chapter':
  childNodes:
    'main':
      constraints:
        nodeTypes:
          'TYPO3.Neos.NodeTypes:Text': true
          '*': false
Examples

Disallow nested Two/Three/FourColumn inside a multi column element:

'TYPO3.Neos.NodeTypes:Column':
  childNodes:
    column0:
      constraints: &columnConstraints
        nodeTypes:
          'TYPO3.Neos.NodeTypes:TwoColumn': false
          'TYPO3.Neos.NodeTypes:ThreeColumn': false
          'TYPO3.Neos.NodeTypes:FourColumn': false
    column1:
      constraints: *columnConstraints
    column2:
      constraints: *columnConstraints
    column3:
      constraints: *columnConstraints
Constraint Specification

To sum it up, the following rules apply:

  • Constraints are only enforced for non-auto-created child nodes.
  • For auto-created child nodes, constraints can be specified for their children as well.
  • NodeTypePattern is usually a Node Type, or * marks the fallback node type.
    • setting the value to true is an explicit allow
    • setting the value to false is an explicit deny
    • setting the value to null (i.e. using ~ in YAML) is an abstain, so that means the fallback of * is used.
  • Inheritance is taking into account, so if allowing/disallowing “Foo”, the subtypes of “Foo” are automatically allowed/disallowed. To constraint subtypes you must be more specific for those types.
  • The default is to always deny (in case “*” is not specified).

Note

Node type constraints are cached in the browser’s session storage. During development, it’s a good idea to run sessionStorage.clear(); in the browser console to remove the old configuration after you make changes.

Translate NodeTypes

To use the translations for NodeType labels or help messages you have to enable it for each label or message by setting the value to the predefined value “i18n”.

NodeTypes.yaml

Vendor.Site:YourContentElementName:
  ui:
    help:
      message: 'i18n'
    inspector:
      tabs:
        yourTab:
          label: 'i18n'
      groups:
        yourGroup:
          label: 'i18n'
  properties:
    yourProperty:
      type: string
        ui:
          label: 'i18n'
          help:
            message: 'i18n'

That will instruct Neos to look for translations of these labels. To register an xliff file for this NodeTypes you have to add the following configuration to the Settings.yaml of your package:

TYPO3:
  Neos:
    userInterface:
      translation:
        autoInclude:
          'Vendor.Site': ['NodeTypes/*']

Inside of the xliff file Resources/Private/Translations/en/NodeTypes/YourContentElementName.xlf the translated labels for help, properties, groups, tabs and views are defined in the xliff as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
        <file original="" product-name="Vendor.Site" source-language="en" datatype="plaintext">
                <body>
                        <trans-unit id="ui.help.message" xml:space="preserve">
                                <source>Your help message here</source>
                        </trans-uni>
                        <trans-unit id="tabs.myTab" xml:space="preserve">
                                <source>Your Tab Title</source>
                        </trans-unit>
                        <trans-unit id="groups.myTab" xml:space="preserve">
                                <source>Your Group Title</source>
                        </trans-unit>
                        <trans-unit id="properties.myProperty" xml:space="preserve">
                                <source>Your Property Title</source>
                        </trans-unit>
                        <trans-unit id="properties.myProperty.ui.help.message" xml:space="preserve">
                                <source>Your help message here</source>
                        </trans-uni>
                </body>
        </file>
</xliff>
Add properties to existing NodeTypes

For adding properties to existing NodeTypes the use of mixins is encouraged.

NodeTypes.yaml

Vendor.Site:YourNodetypeMixin:
  abstract: true
  properties:
    demoProperty:
      type: string
        ui:
          label: 'i18n'

TYPO3.Neos:Page:
  superTypes:
    'Vendor.Site:YourNodetypeMixin': true

That way you can add the translations for the added properties to the file Resources/Private/Translations/en/NodeTypes/YourNodetypeMixin.xlf.

Override Translations

To override translations entirely or to use custom id’s the label property can also contain a path of the format Vendor.Package:Xliff.Path.And.Filename:labelType.identifier. The string consists of three parts delimited by ::

  • First, the Package Key
  • Second, the path towards the xliff file, replacing slashes by dots (relative to Resources/Private/Translation/<language>).
  • Third, the key inside the xliff file.

For the example above that would be Vendor.Site:NodeTypes.YourContentElementName:properties.title:

properties:
  title:
    type: string
      ui:
        label: 'Vendor.Site:NodeTypes.YourContentElementName:properties.title'

If you e.g. want to relabel an existing node property of a different package (like the TYPO3.Neos.NodeTypes:Page), you always have to specify the full translation key (pointing to your package’s XLIFF files then).

Validate Translations

To validate that all labels are translated Neos has the following setting in Settings.yaml:

TYPO3:
  Neos:
    UserInterface:
      scrambleTranslatedLabels: true

If that setting is enabled all already translated labels are replaced with ###### – that way you can easily identify the labels that still lack translations.

Note

Make sure to flush the browser caches after working with the translation to make sure that the browser always shows the latest translations.

Depending Properties

Note

This API is still experimental, we might change details about the handler signature and implementation to reduce the amount of exposed internal code. The UI code is undergoing major changes right now which also might make adjustments necessary.

Sometimes it might be necessary to depend one property editor on another, such as two select boxes where one selection is not meaningful without the other. For that you can setup listeners that get triggered each time a property changes.

Here is an example of the configuration:

'Some.Package:NodeType':
  properties:
    border-width:
      type: integer
    border-color:
      type: string
      ui:
        label: i18n
        inspector:
          editorListeners:
            activeWithNonEmptyValue:
              property: 'border-width'
              handler: 'Some.Package/Handlers/BorderHandler'
              handlerOptions:
                something: true

This sets up a listener named activeWithNonEmptyValue. The name can be freely chosen. This allows to override specific listeners in other packages by refering to that name. The property setting defines the name of the property on the same Node that will be observed. That means any change to this property will trigger the configured handler.

Configuring the handler means defining a require path to the handler object just like with Custom Editors for properties. Namespaces can be registered like this:

TYPO3:
  Neos:
    userInterface:
      requireJsPathMapping:
        'Some.Package/Handlers': 'resource://Some.Package/Public/Scripts/Inspector/Handlers'

The handler should be compatible to RequireJS and be an Ember.Object that has a handle function. The handlerOptions configured for the listener in the NodeType configuration will be given to the handler upon creation and are available in the handle method.

A code example for a handler:

define(
[
    'emberjs'
],
function (Ember) {
    return Ember.Object.extend({
        handle: function(listeningEditor, newValue, property, listenerName) {
            if (this.get('something') === true) {
                listeningEditor.set('disabled', (newValue === null || newValue === ''));
            }
        }
    });
});

The handle function receives the following arguments:

  • listeningEditor - The property editor this listener is configured for, in the above example it will be the border-color editor.
  • newValue will be the value of the observed property, which is the border-width probpery in the above example.
  • property is the name of the observed property, literally border-width in the above example.
  • listenerName is the configured name of the listener in question, literally activeWithNonEmptyValue in the example above.

If you are using select box editors with data sources (see Data sources for more details) you can use editor listeners to adjust dataSourceAdditionalData when properties are changed in the inspector. The following example shows this. It defines two properties (serviceType and contractType) where changes to the first property cause the searchTerm on the second properties’ data source to be updated. That in turn triggers a refresh of the available options from the data source.

properties:
  serviceType:
    type: string
    ui:
      label: 'Service Type'
      inspector:
        group: product
        editor: 'Content/Inspector/Editors/SelectBoxEditor'
        editorOptions:
          allowEmpty: true
          placeholder: 'Service Type'
          dataSourceIdentifier: 'acme-servicetypes'
  contractType:
    type: string
    ui:
      label: 'Contract Type'
      inspector:
        group: product
        editor: 'Content/Inspector/Editors/SelectBoxEditor'
        editorOptions:
          allowEmpty: true
          placeholder: 'Contract Type'
          dataSourceIdentifier: 'acme-contracttypes'
          dataSourceAdditionalData:
            searchTerm: ~
        editorListeners:
          updateForSourceData:
            property: 'serviceType'
            handler: 'Neos.Demo/Handlers/TeaserOptionsHandler'
define(['emberjs'], function (Ember) {
  return Ember.Object.extend({
    handle: function(listeningEditor, newValue, property, listenerName) {
      listeningEditor.set('dataSourceAdditionalData.searchTerm', newValue);
    }
  });
});

TypoScript

Inside TypoScript

In this chapter, TypoScript will be explained in a step-by-step fashion, focusing on the different internal parts, the syntax of these and the semantics.

TypoScript is fundamentally a hierarchical, prototype based processing language:

  • It is hierarchical because the content it should render is also hierarchically structured.
  • It is prototype based because it allows to define properties for all instances of a certain TypoScript object type. It is also possible to define properties not for all instances, but only for instances inside a certain hierarchy. Thus, the prototype definitions are hierarchically-scoped as well.
  • It is a processing language because it processes the values in the context into a single output value.

In the first part of this chapter, the syntactic and semantic features of the TypoScript, Eel and FlowQuery languages are explained. Then, the focus will be on the design decisions and goals of TypoScript, to provide a better understanding of the main objectives while designing the language.

Goals of TypoScript

TypoScript should cater to both planned and unplanned extensibility. This means it should provide ways to adjust and extend its behavior in places where this is to be expected. At the same time it should also be possible to adjust and extend in any other place without having to apply dirty hacks.

TypoScript should be usable in standalone, extensible applications outside of Neos. The use of a flexible language for configuration of (rendering) behavior is beneficial for most complex applications.

TypoScript should make out-of-band rendering easy to do. This should ease content generation for technologies like AJAX or edge-side includes (ESI).

TypoScript should make multiple renderings of the same content possible. It should allow placement of the same content (but possibly in different representations) on the same page multiple times.

TypoScript’s syntax should be familiar to the user, so that existing knowledge can be leveraged. To achieve this, TypoScript takes inspiration from CSS selectors, jQuery and other technologies that are in widespread use in modern frontend development.

TypoScript files

TypoScript is read from files. In the context of Neos, some of these files are loaded automatically, and TypoScript files can be split into parts to organize things as needed.

Automatic TypoScript file inclusion

All TypoScript files are expected to be in the folder Resources/Private/TypoScript when it comes to automatic inclusion.

Neos will include the Root.ts2 file of all packages listed in the Setting TYPO3.Neos.typoScript.autoInclude in the order of packages as returned by the package management.

Neos will then always include the Root.ts2 file of the current site package.

Manual TypoScript file inclusion

In any TypoScript file further files can be included using the include statement. The path is either relative to the current file or can be given with the resource wrapper:

include: NodeTypes/CustomElements.ts2
include: resource://Acme.Demo/Private/TypoScript/Quux.ts2

In addition to giving exact filenames, globbing is possible in two variants:

# Include all .ts2 files in NodeTypes
include: NodeTypes/*

# Include all .ts2 files in NodeTypes and it's subfolders recursively
include: NodeTypes/**/*

The first includes all TypoScript files in the NodeTypes folder, the latter will recursively include all TypoScript files in NodeTypes and any folders below.

The globbing can be combined with the resource wrapper:

include: resource://Acme.Demo/Private/TypoScript/NodeTypes/*
include: resource://Acme.Demo/Private/TypoScript/**/*
TypoScript Objects

TypoScript is a language to describe TypoScript objects. A TypoScript object has some properties which are used to configure the object. Additionally, a TypoScript object has access to a context, which is a list of variables. The goal of a TypoScript object is to take the variables from the context, and transform them to the desired output, using its properties for configuration as needed.

Thus, TypoScript objects take some input which is given through the context and the properties, and produce a single output value. Internally, they can modify the context, and trigger rendering of nested TypoScript objects: This way, a big task (like rendering a whole web page) can be split into many smaller tasks (render a single image, render some text, …): The results of the small tasks are then put together again, forming the final end result.

TypoScript object nesting is a fundamental principle of TypoScript. As TypoScript objects call nested TypoScript objects, the rendering process forms a tree of TypoScript objects.

TypoScript objects are implemented by a PHP class, which is instantiated at runtime. A single PHP class is the basis for many TypoScript objects. We will highlight the exact connection between TypoScript objects and their PHP implementations later.

A TypoScript object can be instantiated by assigning it to a TypoScript path, such as:

foo = Page
# or:
my.object = Text
# or:
my.image = TYPO3.Neos.ContentTypes:Image

The name of the to-be-instantiated TypoScript prototype is listed without quotes.

By convention, TypoScript paths (such as my.object) are written in lowerCamelCase, while TypoScript prototypes (such as TYPO3.Neos.ContentTypes:Image) are written in UpperCamelCase.

It is possible to set properties on the newly created TypoScript objects:

foo.myProperty1 = 'Some Property which Page can access'
my.object.myProperty1 = "Some other property"
my.image.width = ${q(node).property('foo')}

Property values that are strings have to be quoted (with either single or double quotes). A property can also be an Eel expression (which are explained in Eel, FlowQuery and Fizzle.)

To reduce typing overhead, curly braces can be used to “abbreviate” long TypoScript paths:

my {
  image = Image
  image.width = 200

  object {
    myProperty1 = 'some property'
  }
}

Instantiating a TypoScript object and setting properties on it in a single pass is also possible. All three examples mean exactly the same:

someImage = Image
someImage.foo = 'bar'

# Instantiate object, set property one after each other
someImage = Image
someImage {
  foo = 'bar'
}

# Instantiate an object and set properties directly
someImage = Image {
  foo = 'bar'
}
TypoScript Objects are Side-Effect Free

When TypoScript objects are rendered, they are allowed to modify the TypoScript context (they can add or override variables); and can invoke other TypoScript objects. After rendering, however, the parent TypoScript object must make sure to clean up the context, so that it contains exactly the state it had before the rendering.

The API helps to enforce this, as the TypoScript context is a stack: The only thing the developer of a TypoScript object needs to make sure is that if he adds some variable to the stack, effectively creating a new stack frame, he needs to remove exactly this stack frame after rendering again.

This means that a TypoScript object can only manipulate TypoScript objects below it, but not following or preceding it.

In order to enforce this, TypoScript objects are furthermore only allowed to communicate through the TypoScript Context; and they are never allowed to be invoked directly: Instead, all invocations need to be done through the TypoScript Runtime.

All these constraints make sure that a TypoScript object is side-effect free, leading to an important benefit: If somebody knows the exact path towards a TypoScript object together with its context, it can be rendered in a stand-alone manner, exactly as if it was embedded in a bigger element. This enables, for example, rendering parts of pages with different cache life- times, or the effective implementation of AJAX or ESI handlers reloading only parts of a website.

TypoScript Prototypes

When a TypoScript object is instantiated (i.e. when you type someImage = Image) the TypoScript Prototype for this object is copied and is used as a basis for the new object. The prototype is defined using the following syntax:

prototype(MyImage) {
        width = '500px'
        height = '600px'
}

When the above prototype is instantiated, the instantiated object will have all the properties of the copied prototype. This is illustrated through the following example:

someImage = MyImage
# now, someImage will have a width of 500px and a height of 600px

someImage.width = '100px'
# now, we have overridden the height of "someImage" to be 100px.

Prototype- vs. class-based languages

There are generally two major “flavours” of object-oriented languages. Most languages (such as PHP, Ruby, Perl, Java, C++) are class-based, meaning that they explicitly distinguish between the place where behavior for a given object is defined (the “class”) and the runtime representation which contains the data (the “instance”).

Other languages such as JavaScript are prototype-based, meaning that there is no distinction between classes and instances: At object creation time, all properties and methods of the object’s prototype (which roughly corresponds to a “class”) are copied (or otherwise referenced) to the instance.

TypoScript is a prototype-based language because it copies the TypoScript Prototype to the instance when an object is evaluated.

Prototypes in TypoScript are mutable, which means that they can easily be modified:

prototype(MyYouTube) {
        width = '100px'
        height = '500px'
}

# you can change the width/height
prototype(MyYouTube).width = '400px'
# or define new properties:
prototype(MyYouTube).showFullScreen = ${true}

Defining and instantiating a prototype from scratch is not the only way to define and instantiate them. You can also use an existing TypoScript prototype as basis for a new one when needed. This can be done by inheriting from a TypoScript prototype using the < operator:

prototype(MyImage) < prototype(TYPO3.Neos:Content)

# now, the MyImage prototype contains all properties of the Template
# prototype, and can be further customized.

This implements prototype inheritance, meaning that the “subclass” (MyImage in the example above) and the “parent class (Content) are still attached to each other: If a property is added to the parent class, this also applies to the subclass, as in the following example:

prototype(TYPO3.Neos:Content).fruit = 'apple'
prototype(TYPO3.Neos:Content).meal = 'dinner'

prototype(MyImage) < prototype(TYPO3.Neos:Content)
# now, MyImage also has the properties "fruit = apple" and "meal = dinner"

prototype(TYPO3.Neos:Content).fruit = 'Banana'
# because MyImage *extends* Content, MyImage.fruit equals 'Banana' as well.

prototype(MyImage).meal = 'breakfast'
prototype(TYPO3.TypoScript:Content).meal = 'supper'
# because MyImage now has an *overridden* property "meal", the change of
# the parent class' property is not reflected in the MyImage class

Prototype inheritance can only be defined globally, i.e. with a statement of the following form:

prototype(Foo) < prototype(Bar)

It is not allowed to nest prototypes when defining prototype inheritance, so the following examples are not valid TypoScript and will result in an exception:

prototype(Foo) < some.prototype(Bar)
other.prototype(Foo) < prototype(Bar)
prototype(Foo).prototype(Bar) < prototype(Baz)

While it would be theoretically possible to support this, we have chosen not to do so in order to reduce complexity and to keep the rendering process more understandable. We have not yet seen a TypoScript example where a construct such as the above would be needed.

Hierarchical TypoScript Prototypes

One way to flexibly adjust the rendering of a TypoScript object is done through modifying its Prototype in certain parts of the rendering tree. This is possible because TypoScript prototypes are hierarchical, meaning that prototype(...) can be part of any TypoScript path in an assignment; even multiple times:

prototype(Foo).bar = 'baz'
prototype(Foo).some.thing = 'baz2'

some.path.prototype(Foo).some = 'baz2'

prototype(Foo).prototype(Bar).some = 'baz2'
prototype(Foo).left.prototype(Bar).some = 'baz2'
  • prototype(Foo).bar is a simple, top-level prototype property assignment. It means: For all objects of type Foo, set property bar. The second example is another variant of this pattern, just with more nesting levels inside the property assignment.
  • some.path.prototype(Foo).some is a prototype property assignment inside some.path. It means: For all objects of type Foo which occur inside the TypoScript path some.path, the property some is set.
  • prototype(Foo).prototype(Bar).some is a prototype property assignment inside another prototype. It means: For all objects of type Bar which occur somewhere inside an object of type Foo, the property some is set.
  • This can both be combined, as in the last example inside prototype(Foo).left.prototype(Bar).some.

Internals of hierarchical prototypes

A TypoScript object is side-effect free, which means that it can be rendered deterministically knowing only its TypoScript path and the context. In order to make this work with hierarchical prototypes, we need to encode the types of all TypoScript objects above the current one into the current path. This is done using angular brackets:

a1/a2<Foo>/a3/a4<Bar>

When this path is rendered, a1/a2 is rendered as a TypoScript object of type Foo – which is needed to apply the prototype inheritance rules correctly.

Those paths are rarely visible on the “outside” of the rendering process, but might at times appear in exception messages if rendering fails. For those cases it is helpful to know their semantics.

Bottom line: It is not important to know exactly how the a rendering TypoScript object’s TypoScript path is constructed. Just pass it on, without modification to render a single element out of band.

Namespaces of TypoScript objects

The benefits of namespacing apply just as well to TypoScript objects as they apply to other languages. Namespacing helps to organize the code and avoid name clashes.

In TypoScript the namespace of a prototype is given when the prototype is declared. The following declares a YouTube prototype in the Acme.Demo namespace:

prototype(Acme.Demo:YouTube) {
        width = '100px'
        height = '500px'
}

The namespace is, by convention, the package key of the package in which the TypoScript resides.

Fully qualified identifiers can be used everywhere an identifier is used:

prototype(TYPO3.Neos:ContentCollection) < prototype(TYPO3.Neos:Collection)

In Neos TypoScript a default namespace of TYPO3.Neos is set. So whenever Page is used in TypoScript within Neos, it is a shortcut for TYPO3.Neos:Page.

Custom namespace aliases can be defined using the following syntax:

namespace: Foo = Acme.Demo

# the following two lines are equivalent now
video = Acme.Demo:YouTube
video = Foo:YouTube

Warning

These declarations are not scoped to the file they are in, but apply globally (at least currently, we plan to change that in the future). So you should be careful there!

Setting Properties On a TypoScript Object

Although the TypoScript object can read its context directly, it is good practice to instead use properties for configuration:

# imagine there is a property "foo=bar" inside the TypoScript context at this point
myObject = MyObject

# explicitly take the "foo" variable's value from the context and pass it into the "foo"
# property of myObject. This way, the flow of data is more visible.
myObject.foo = ${foo}

While myObject could rely on the assumption that there is a foo variable inside the TypoScript context, it has no way (besides written documentation) to communicate this to the outside world.

Therefore, a TypoScript object’s implementation should only use properties of itself to determine its output, and be independent of what is stored in the context.

However, in the prototype of a TypoScript object it is perfectly legal to store the mapping between the context variables and TypoScript properties, such as in the following example:

# this way, an explicit default mapping between a context variable and a property of the
# TypoScript object is created.
prototype(MyObject).foo = ${foo}

To sum it up: When implementing a TypoScript object, it should not access its context variables directly, but instead use a property. In the TypoScript object’s prototype, a default mapping between a context variable and the prototype can be set up.

Default Context Variables

Neos exposes some default variables to the TypoScript context that can be used to control page rendering in a more granular way.

  • node can be used to get access to the current node in the node tree and read its properties. It is of type NodeInterface and can be used to work with node data, such as:

    # Make the node available in the template
    node = ${node}
    
    # Expose the "backgroundImage" property to the rendering using FlowQuery
    backgroundImage = ${q(node).property('backgroundImage')}
    

    To see what data is available on the node, you can expose it to the template as above and wrap it in a debug view helper:

    {node -> f:debug()}
    
  • documentNode contains the closest parent document node - broadly speaking, it is the page the current node is on. Just like node, it is a NodeInterface and can be provided to the rendering in the same way:

    # Expose the document node to the template
    documentNode = ${documentNode}
    
    # Display the document node path
    nodePath = ${documentNode.path}
    

    documentNode is in the end just a shorthand to get the current document node faster. It could be replaced with:

    # Expose the document node to the template using FlowQuery and a Fizzle operator
    documentNode = ${q(node).closest('[instanceof TYPO3.Neos:Document]').get(0)}
    
  • request is an instance of TYPO3\Flow\Mvc\ActionRequest and allows you to access the current request from within TypoScript. Use it to provide request variables to the template:

    # This would provide the value sent by an input field with name="username".
    userName = ${request.arguments.username}
    
    # request.format contains the format string of the request, such as "html" or "json"
    requestFormat = ${request.format}
    

    Another use case is to trigger an action, e.g. a search, via a custom Eel helper:

    searchResults = ${Search.query(site).fulltext(request.arguments.searchword).execute()}
    

    A word of caution: You should never trigger write operations from TypoScript, since it can be called multiple times (or not at all, because of caching) during a single page render. If you want a request to trigger a persistent change on your site, it’s better to use a Plugin.

Manipulating the TypoScript Context

The TypoScript context can be manipulated directly through the use of the @context meta-property:

myObject = MyObject
myObject.@context.bar = ${foo * 2}

In the above example, there is now an additional context variable bar with twice the value of foo.

This functionality is especially helpful if there are strong conventions regarding the TypoScript context variables. This is often the case in standalone TypoScript applications, but for Neos, this functionality is hardly ever used.

Processors

Processors allow the manipulation of values in TypoScript properties. A processor is applied to a property using the @process meta-property:

myObject = MyObject {
        property = 'some value'
        property.@process.1 = ${'before ' + value + ' after'}
}
# results in 'before some value after'

Multiple processors can be used, their execution order is defined by the numeric position given in the TypoScript after @process. In the example above a @process.2 would run on the results of @process.1.

Additionally, an extended syntax can be used as well:

myObject = MyObject {
        property = 'some value'
        property.@process.someWrap {
                expression = ${'before ' + value + ' after'}
                @position = 'start'
        }
}

This allows to use string keys for the processor name, and support @position arguments as explained for Arrays.

Processors are Eel Expressions or TypoScript objects operating on the value property of the context. Additionally, they can access the current TypoScript object they are operating on as this.

Conditions

Conditions can be added to all values to prevent evaluation of the value. A condition is applied to a property using the @if meta-property:

myObject = Menu {
        @if.1 = ${q(node).property('showMenu') == true}
}
# results in the menu object only being evaluated if the node's showMenu property is ``true``

Multiple conditions can be used, and if one of them doesn’t return true the condition stops evaluation.

Debugging

To show the result of TypoScript Expressions directly you can use the TYPO3.TypoScript:Debug TypoScript-Object:

debugObject = Debug {
        # optional: set title for the debug output
        # title = 'Debug'

        # optional: show result as plaintext
        # plaintext = TRUE

        # If only the "value"-key is given it is debugged directly,
        # otherwise all keys except "title" and "plaintext" are debugged.
        value = "hello neos world"

        # Additional values for debugging
        documentTitle = ${q(documentNode).property('title')}
        documentPath = ${documentNode.path}
}
# the value of this object is the formatted debug output of all keys given to the object

Eel, FlowQuery and Fizzle

Eel - Embedded Expression Language

Besides simple TypoScript assignments such as myObject.foo = 'bar', it is possible to write expressions using the Eel language such as myObject.foo = ${q(node).property('bar')}.

The Embedded Expression Language (Eel) is a building block for creating Domain Specific Languages. It provides a rich syntax for arbitrary expressions, such that the author of the DSL can focus on its Semantics.

In this section, the focus lies on the use of Eel inside TypoScript.

Syntax

Every Eel expression in TypoScript is surrounded by ${...}, which is the delimiter for Eel expressions. Basically, the Eel syntax and semantics is like a condensed version of JavaScript:

  • Most things you can write as a single JavaScript expression (that is, without a ;) can also be written as Eel expression.
  • Eel does not throw an error if null values are dereferenced, i.e. inside ${foo.bar} with foo being null. Instead, null is returned. This also works for calling undefined functions.
  • Eel does not support control structures or variable declarations.
  • Eel supports the common JavaScript arithmetic and comparison operators, such as +-*/% for arithmetic and == != > >= < <= for comparison operators. Operator precedence is as expected, with multiplication binding higher than addition. This can be adjusted by using brackets. Boolean operators && and || are supported.
  • Eel supports the ternary operator to allow for conditions <condition> ? <ifTrue> : <ifFalse>.
  • When object access is done (such as foo.bar.baz) on PHP objects, getters are called automatically.
  • Object access with the offset notation is supported as well: foo['bar']

This means the following expressions are all valid Eel expressions:

${foo.bar}         // Traversal
${foo.bar()}       // Method call
${foo.bar().baz()} // Chained method call

${foo.bar("arg1", true, 42)} // Method call with arguments

${12 + 18.5}         // Calculations are possible
${foo == bar}      // ... and comparisons

${foo.bar(12+18.5, foo == bar)} // and of course also use it inside arguments

${[foo, bar]}           // Array Literal
${{foo: bar, baz: test}} // Object Literal
Semantics inside TypoScript

Eel does not define any functions or variables by itself. Instead, it exposes the Eel context array, meaning that functions and objects which should be accessible can be defined there.

Because of that, Eel is perfectly usable as a “domain-specific language construction kit”, which provides the syntax, but not the semantics of a given language.

For Eel inside TypoScript, the semantics are as follows:

  • All variables of the TypoScript context are made available inside the Eel context.
  • The special variable this always points to the current TypoScript object implementation.
  • The function q() is available, which wraps its argument into a FlowQuery object. FlowQuery is explained below.

By default the following Eel helpers are available in the default context for Eel expressions:

  • String, exposing TYPO3\Eel\Helper\StringHelper
  • Array, exposing TYPO3\Eel\Helper\ArrayHelper
  • Date, exposing TYPO3\Eel\Helper\DateHelper
  • Configuration, exposing TYPO3\Eel\Helper\ConfigurationHelper
  • Math, exposing TYPO3\Eel\Helper\MathHelper
  • Json, exposing TYPO3\Eel\Helper\JsonHelper
  • Security, exposing TYPO3\Eel\Helper\SecurityHelper
  • Translation, exposing TYPO3\Flow\I18n\EelHelper\TranslationHelper
  • Neos.Node, exposing TYPO3\Neos\TypoScript\Helper\NodeHelper
  • Neos.Link, exposing TYPO3\Neos\TypoScript\Helper\LinkHelper
  • Neos.Array, exposing TYPO3\Neos\TypoScript\Helper\ArrayHelper
  • Neos.Rendering, exposing TYPO3\Neos\TypoScript\Helper\RenderingHelper

See: Eel Helpers Reference

This is configured via the setting TYPO3.TypoScript.defaultContext.

Additionally, the defaultContext contains the request object, where you have also access to Arguments. e.g. ${request.httpRequest.arguments.nameOfYourGetArgument}

FlowQuery

FlowQuery, as the name might suggest, is like jQuery for Flow. It’s syntax has been heavily influenced by jQuery.

FlowQuery is a way to process the content (being a TYPO3CR node within Neos) of the Eel context. FlowQuery operations are implemented in PHP classes. For any FlowQuery operation to be available, the package containing the operation must be installed. Any package can add their own FlowQuery operations. A set of basic operations is always available as part of the TYPO3.Eel package itself.

In TYPO3.Neos, the following FlowQuery operations are defined:

property
Adjusted to access properties of a TYPO3CR node. If property names are prefixed with an underscore, internal node properties like start time, end time, and hidden are accessed.
filter
Used to check a value against a given constraint. The filters expressions are given in Fizzle, a language inspired by CSS selectors. The Neos-specific filter changes instanceof to work on node types instead of PHP classes.
children
Returns the children of a TYPO3CR node. They are optionally filtered with a filter operation to limit the returned result set.
parents
Returns the parents of a TYPO3CR node. They are optionally filtered with a filter operation to limit the returned result set.

A reference of all FlowQuery operations defined in TYPO3.Eel and TYPO3.Neos can be found in the FlowQuery Operation Reference.

Operation Resolving

When multiple packages define an operation with the same short name, they are resolved using the priority each implementation defines, higher priorities have higher precedence when operations are resolved.

The OperationResolver loops over the implementations sorted by order and asks them if they can evaluate the current context. The first operation that answers this check positively is used.

FlowQuery by Example

Any context variable can be accessed directly:

${myContextVariable}

and the current node is available as well:

${node}

There are various ways to access its properties. Direct access is possible, but should be avoided. It is better to use FlowQuery instead:

${q(node).getProperty('foo')} // Possible, but discouraged
${q(node).property('foo')} // Better: use FlowQuery instead

Through this a node property can be fetched and assigned to a variable:

text = ${q(node).property('text')}

Fetching all parent nodes of the current node:

${q(node).parents()}

Here are two equivalent ways to fetch the first node below the left child node:

${q(node).children('left').first()}
${q(node).children().filter('left').first()}

Fetch all parent nodes and add the current node to the selected set:

${node.parents().add(node)}

The next example combines multiple operations. First it fetches all children of the current node that have the name comments. Then it fetches all children of those nodes that have a property spam with a value of false. The result of that is then passed to the count() method and the count of found nodes is assigned to the variable ‘numberOfComments’:

numberOfComments = ${q(node).children('comments').children("[spam = false]").count()}

The following expands a little more on that. It assigns a set of nodes to the collection property of the comments object. This set of nodes is either fetched from different places, depending on whether the current node is a ContentCollection node or not. If it is, the children of the current node are used directly. If not, the result of this.getNodePath() is used to fetch a node below the current node and those children are used. In both cases the nodes are again filtered by a check for their property spam being false.

comments.collection = ${q(node).is('[instanceof TYPO3.Neos:ContentCollection]') ?
        q(node).children("[spam = false]") : q(node).children(this.getNodePath()).children("[spam = false]")}
Fizzle

Filter operations as already shown are written in Fizzle. It has been inspired by the selector syntax known from CSS.

Property Name Filters

The first component of a filter query can be a Property Name filter. It is given as a simple string. Checks against property paths are not currently possible:

foo          //works
foo.bar      //does not work
foo.bar.baz  //does not work

In the context of Neos the property name is rarely used, as FlowQuery operates on TYPO3CR nodes and the children operation has a clear scope. If generic PHP objects are used, the property name filter is essential to define which property actually contains the children.

Attribute Filters

The next component are Attribute filters. They can check for the presence and against the values of attributes of context elements:

baz[foo]
baz[answer = 42]
baz[foo = "Bar"]
baz[foo = 'Bar']
baz[foo != "Bar"]
baz[foo ^= "Bar"]
baz[foo $= "Bar"]
baz[foo *= "Bar"]

As the above examples show, string values can be quoted using double or single quotes.

Available Operators

The operators for checking against attribute are as follows:

=
Strict equality of value and operand
!=
Strict inequality of value and operand
$=
Value ends with operand (string-based)
^=
Value starts with operand (string-based)
*=
Value contains operand (string-based)
instanceof
Checks if the value is an instance of the operand

For the latter the behavior is as follows: if the operand is one of the strings object, array, int(eger), float, double, bool(ean) or string the value is checked for being of the specified type. For any other strings the value is used as class name with the PHP instanceof operation to check if the value matches.

Using Multiple Filters

It is possible to combine multiple filters:

[foo][bar][baz]
All filters have to match (AND)
[foo],[bar],[baz]
Only one filter has to match (OR)

Rendering Custom Markup

These are the development guidelines of Neos.

Templating

Templating is done in Fluid, which is a next-generation templating engine. It has several goals in mind:

  • Simplicity
  • Flexibility
  • Extensibility
  • Ease of use

This templating engine should not be bloated, instead, we try to do it “The Zen Way” - you do not need to learn too many things, thus you can concentrate on getting your things done, while the template engine handles everything you do not want to care about.

What Does it Do?

In many MVC systems, the view currently does not have a lot of functionality. The standard view usually provides a render method, and nothing more. That makes it cumbersome to write powerful views, as most designers will not write PHP code.

That is where the Template Engine comes into play: It “lives” inside the View, and is controlled by a special TemplateView which instantiates the Template Parser, resolves the template HTML file, and renders the template afterwards.

Below, you’ll find a snippet of a real-world template displaying a list of blog postings. Use it to check whether you find the template language intuitive:

{namespace f=TYPO3\Fluid\ViewHelpers}
<html>
<head><title>Blog</title></head>
<body>
<h1>Blog Postings</h1>
<f:for each="{postings}" as="posting">
  <h2>{posting.title}</h2>
  <div class="author">{posting.author.name} {posting.author.email}</div>
  <p>
    <f:link.action action="details" arguments="{id : posting.id}">
      {posting.teaser}
    </f:link.action>
  </p>
</f:for>
</body>
</html>
  • The Namespace Import makes the \TYPO3\Fluid\ViewHelper namespace available under the shorthand f.
  • The <f:for> essentially corresponds to foreach ($postings as $posting) in PHP.
  • With the dot-notation ({posting.title} or {posting.author.name}), you can traverse objects. In the latter example, the system calls $posting->getAuthor()->getName().
  • The <f:link.action /> tag is a so-called ViewHelper. It calls arbitrary PHP code, and in this case renders a link to the “details”-Action.

There is a lot more to show, including:

  • Layouts
  • Custom View Helpers
  • Boolean expression syntax

We invite you to explore Fluid some more, and please do not hesitate to give feedback!

Basic Concepts

This section describes all basic concepts available. This includes:

  • Namespaces
  • Variables / Object Accessors
  • View Helpers
  • Arrays
Namespaces

Fluid can be extended easily, thus it needs a way to tell where a certain tag is defined. This is done using namespaces, closely following the well-known XML behavior.

Namespaces can be defined in a template in two ways:

{namespace f=TYPO3FluidViewHelpers}
This is a non-standard way only understood by Fluid. It links the f prefix to the PHP namespace \TYPO3\Fluid\ViewHelpers.
<html xmlns:foo=”http://some/unique/namespace”>
The standard for declaring a namespace in XML. This will link the foo prefix to the URI http://some/unique/namespace and Fluid can look up the corresponding PHP namespace in your settings (so this is a two-piece configuration). This makes it possible for your XML editor to validate the template files and even use an XSD schema for auto completion.

A namespace linking f to \TYPO3\Fluid\ViewHelpers is imported by default. All other namespaces need to be imported explicitly.

If using the XML namespace syntax the default pattern http://typo3.org/ns/<php namespace> is resolved automatically by the Fluid parser. If you use a custom XML namespace URI you need to configure the URI to PHP namespace mapping. The YAML syntax for that is:

TYPO3:
  Fluid:
    namespaces:
      'http://some/unique/namespace': 'My\Php\Namespace'
Variables and Object Accessors

A templating system would be quite pointless if it was not possible to display some external data in the templates. That’s what variables are for.

Suppose you want to output the title of your blog, you could write the following snippet into your controller:

$this->view->assign('blogTitle', $blog->getTitle());

Then, you could output the blog title in your template with the following snippet:

<h1>This blog is called {blogTitle}</h1>

Now, you might want to extend the output by the blog author as well. To do this, you could repeat the above steps, but that would be quite inconvenient and hard to read.

Note

The semantics between the controller and the view should be the following: The controller instructs the view to “render the blog object given to it”, and not to “render the Blog title, and the blog posting 1, …”.

Passing objects to the view instead of simple values is highly encouraged!

That is why the template language has a special syntax for object access. A nicer way of expressing the above is the following:

// This should go into the controller:
$this->view->assign('blog', $blog);
<!-- This should go into the template: -->
<h1>This blog is called {blog.title}, written by {blog.author}</h1>

Instead of passing strings to the template, we are passing whole objects around now - which is much nicer to use both from the controller and the view side. To access certain properties of these objects, you can use Object Accessors. By writing {blog.title}, the template engine will call a getTitle() method on the blog object, if it exists. Besides, you can use that syntax to traverse associative arrays and public properties.

Tip

Deep nesting is supported: If you want to output the email address of the blog author, then you can use {blog.author.email}, which is roughly equivalent to $blog->getAuthor()->getEmail().

View Helpers

All output logic is placed in View Helpers.

The view helpers are invoked by using XML tags in the template, and are implemented as PHP classes (more on that later).

This concept is best understood with an example:

{namespace f=TYPO3\Fluid\ViewHelpers}
<f:link.action controller="Administration">Administration</f:link.action>

The example consists of two parts:

  • Namespace Declaration as explained earlier.
  • Calling the View Helper with the <f:link.action...> ... </f:link.action> tag renders a link.

Now, the main difference between Fluid and other templating engines is how the view helpers are implemented: For each view helper, there exists a corresponding PHP class. Let’s see how this works for the example above:

The <f:link.action /> tag is implemented in the class \TYPO3\Fluid\ViewHelpers\Link\ActionViewHelper.

Note

The class name of such a view helper is constructed for a given tag as follows:

  1. The first part of the class name is the namespace which was imported (the namespace prefix f was expanded to its full namespace TYPO3\Fluid\ViewHelpers)
  2. The unqualified name of the tag, without the prefix, is capitalized (Link), and the postfix ViewHelper is appended.

The tag and view helper concept is the core concept of Fluid. All output logic is implemented through such ViewHelpers / tags! Things like if/else, for, … are all implemented using custom tags - a main difference to other templating languages.

Note

Some benefits of the class-based approach approach are:

  • You cannot override already existing view helpers by accident.
  • It is very easy to write custom view helpers, which live next to the standard view helpers
  • All user documentation for a view helper can be automatically generated from the annotations and code documentation.

Most view helpers have some parameters. These can be plain strings, just like in <f:link.action controller="Administration">...</f:link.action>, but as well arbitrary objects. Parameters of view helpers will just be parsed with the same rules as the rest of the template, thus you can pass arrays or objects as parameters.

This is often used when adding arguments to links:

<f:link.action controller="Blog" action="show" arguments="{singleBlog: blogObject}">
  ... read more
</f:link.action>

Here, the view helper will get a parameter called arguments which is of type array.

Warning

Make sure you do not put a space before or after the opening or closing brackets of an array. If you type arguments=" {singleBlog : blogObject}" (notice the space before the opening curly bracket), the array is automatically casted to a string (as a string concatenation takes place).

This also applies when using object accessors: <f:do.something with="{object}" /> and <f:do.something with=" {object}" /> are substantially different: In the first case, the view helper will receive an object as argument, while in the second case, it will receive a string as argument.

This might first seem like a bug, but actually it is just consistent that it works that way.

Boolean Expressions

Often, you need some kind of conditions inside your template. For them, you will usually use the <f:if> ViewHelper. Now let’s imagine we have a list of blog postings and want to display some additional information for the currently selected blog posting. We assume that the currently selected blog is available in {currentBlogPosting}. Now, let’s have a look how this works:

<f:for each="{blogPosts}" as="post">
  <f:if condition="{post} == {currentBlogPosting}">... some special output here ...</f:if>
</f:for>

In the above example, there is a bit of new syntax involved: {post} == {currentBlogPosting}. Intuitively, this says “if the post I’‘m currently iterating over is the same as currentBlogPosting, do something.”

Why can we use this boolean expression syntax? Well, because the IfViewHelper has registered the argument condition as boolean. Thus, the boolean expression syntax is available in all arguments of ViewHelpers which are of type boolean.

All boolean expressions have the form X <comparator> Y, where:

  • <comparator> is one of the following: ==, >, >=, <, <=, % (modulo)
  • X and Y are one of the following:
    • a number (integer or float)
    • a string (in single or double quotes)
    • a JSON array
    • a ViewHelper
    • an Object Accessor (this is probably the most used example)
    • inline notation for ViewHelpers
Inline Notation for ViewHelpers

In many cases, the tag-based syntax of ViewHelpers is really intuitive, especially when building loops, or forms. However, in other cases, using the tag-based syntax feels a bit awkward – this can be demonstrated best with the <f:uri.resource>- ViewHelper, which is used to reference static files inside the Public/ folder of a package. That’s why it is often used inside <style> or <script>-tags, leading to the following code:

<link rel="stylesheet" href="<f:uri.resource path='myCssFile.css' />" />

You will notice that this is really difficult to read, as two tags are nested into each other. That’s where the inline notation comes into play: It allows the usage of {f:uri.resource()} instead of <f:uri.resource />. The above example can be written like the following:

<link rel="stylesheet" href="{f:uri.resource(path:'myCssFile.css')}" />

This is readable much better, and explains the intent of the ViewHelper in a much better way: It is used like a helper function.

The syntax is still more flexible: In real-world templates, you will often find code like the following, formatting a DateTime object (stored in {post.date} in the example below):

<f:format.date format="d-m-Y">{post.date}</f:format.date>

This can also be re-written using the inline notation:

{post.date -> f:format.date(format:'d-m-Y')}

This is also a lot better readable than the above syntax.

Tip

This can also be chained indefinitely often, so one can write:

{post.date -> foo:myHelper() -> bar:bla()}

Sometimes you’ll still need to further nest ViewHelpers, that is when the design of the ViewHelper does not allow that chaining or provides further arguments. Have in mind that each argument itself is evaluated as Fluid code, so the following constructs are also possible:

{foo: bar, baz: '{planet.manufacturer -> f:someother.helper(test: \'stuff\')}'}
{some: '{f:format.stuff(arg: \'foo'\)}'}

To wrap it up: Internally, both syntax variants are handled equally, and every ViewHelper can be called in both ways. However, if the ViewHelper “feels” like a tag, use the tag-based notation, if it “feels” like a helper function, use the Inline Notation.

Arrays

Some view helpers, like the SelectViewHelper (which renders an HTML select dropdown box), need to get associative arrays as arguments (mapping from internal to displayed name). See the following example for how this works:

<f:form.select options="{edit: 'Edit item', delete: 'Delete item'}" />

The array syntax used here is very similar to the JSON object syntax. Thus, the left side of the associative array is used as key without any parsing, and the right side can be either:

  • a number:

    {a : 1,
     b : 2
    }
    
  • a string; Needs to be in either single- or double quotes. In a double-quoted string, you need to escape the " with a \ in front (and vice versa for single quoted strings). A string is again handled as Fluid Syntax, this is what you see in example c:

    {a : 'Hallo',
     b : "Second string with escaped \" (double quotes) but not escaped ' (single quotes)"
     c : "{firstName} {lastName}"
    }
    
  • a boolean, best represented with their integer equivalents:

    {a : 'foo',
     notifySomebody: 1
     useLogging: 0
    }
    
  • a nested array:

    {a : {
            a1 : "bla1",
            a2 : "bla2"
      },
     b : "hallo"
    }
    
  • a variable reference (=an object accessor):

    {blogTitle : blog.title,
     blogObject: blog
    }
    

Note

All these array examples will result into an associative array. If you have to supply a non-associative, i.e. numerically-indexed array, you’ll write {0: 'foo', 1: 'bar', 2: 'baz'}.

Passing Data to the View

You can pass arbitrary objects to the view, using $this->view->assign($identifier, $object) from within the controller. See the above paragraphs about Object Accessors for details how to use the passed data.

Layouts

In almost all web applications, there are many similarities between each page. Usually, there are common templates or menu structures which will not change for many pages.

To make this possible in Fluid, we created a layout system, which we will introduce in this section.

Writing a Layout

Every layout is placed in the Resources/Private/Layouts directory, and has the file ending of the current format (by default .html). A layout is a normal Fluid template file, except there are some parts where the actual content of the target page should be inserted:

<html>
<head><title>My fancy web application</title></head>
<body>
<div id="menu">... menu goes here ...</div>
<div id="content">
  <f:render section="content" />
</div>
</body>
</html>

With this tag, a section from the target template is rendered.

Using a Layout

Using a layout involves two steps:

  • Declare which layout to use: <f:layout name="..." /> can be written anywhere on the page (though we suggest to write it on top, right after the namespace declaration) - the given name references the layout.
  • Provide the content for all sections used by the layout using the <f:section>...</f:section> tag: <f:section name="content">...</f:section>

For the above layout, a minimal template would look like the following:

<f:layout name="example.html" />

<f:section name="content">
  This HTML here will be outputted to inside the layout
</f:section>
Writing Your Own ViewHelper

As we have seen before, all output logic resides in View Helpers. This includes the standard control flow operators such as if/else, HTML forms, and much more. This is the concept which makes Fluid extremely versatile and extensible.

If you want to create a view helper which you can call from your template (as a tag), you just write a plain PHP class which needs to inherit from TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper (or its subclasses). You need to implement only one method to write a view helper:

public function render()
Rendering the View Helper

We refresh what we have learned so far: When a user writes something like <blog:displayNews /> inside a template (and has imported the blog namespace to TYPO3\Blog\ViewHelpers), Fluid will automatically instantiate the class TYPO3\Blog\ViewHelpers\DisplayNewsViewHelper, and invoke the render() method on it.

This render() method should return the rendered content as string.

You have the following possibilities to access the environment when rendering your view helper:

  • $this->arguments is an associative array where you will find the values for all arguments you registered previously.
  • $this->renderChildren() renders everything between the opening and closing tag of the view helper and returns the rendered result (as string).
  • $this->templateVariableContainer is an instance of TYPO3\Fluid\Core\ViewHelper\TemplateVariableContainer, with which you have access to all variables currently available in the template, and can modify the variables currently available in the template.

Note

If you add variables to the TemplateVariableContainer, make sure to remove every variable which you added again. This is a security measure against side-effects.

It is also not possible to add a variable to the TemplateVariableContainer if a variable of the same name already exists - again to prevent side effects and scope problems.

Implementing a for ViewHelper

Now, we will look at an example: How to write a view helper giving us the foreach functionality of PHP.

A loop could be called within the template in the following way:

<f:for each="{blogPosts}" as="blogPost">
  <h2>{blogPost.title}</h2>
</f:for>

So, in words, what should the loop do?

It needs two arguments:

  • each: Will be set to some object or array which can be iterated over.
  • as: The name of a variable which will contain the current element being iterated over

It then should do the following (in pseudo code):

foreach ($each as $$as) {
  // render everything between opening and closing tag
}

Implementing this is fairly straightforward, as you will see right now:

class ForViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper {

  /**
   * Renders a loop
   *
   * @param array $each Array to iterate over
   * @param string $as Iteration variable
   */
  public function render(array $each, $as) {
        $out = '';
        foreach ($each as $singleElement) {
          $this->variableContainer->add($as, $singleElement);
          $out .= $this->renderChildren();
          $this->variableContainer->remove($as);
        }
        return $out;
  }

}
  • The PHPDoc is part of the code! Fluid extracts the argument data types from the PHPDoc.
  • You can simply register arguments to the view helper by adding them as method arguments of the render() method.
  • Using $this->renderChildren(), everything between the opening and closing tag of the view helper is rendered and returned as string.
Declaring Arguments

We have now seen that we can add arguments just by adding them as method arguments to the render() method. There is, however, a second method to register arguments.

You can also register arguments inside a method called initializeArguments(). Call $this->registerArgument($name, $dataType, $description, $isRequired, $defaultValue=NULL) inside.

It depends how many arguments a view helper has. Sometimes, registering them as render() arguments is more beneficial, and sometimes it makes more sense to register them in initializeArguments().

AbstractTagBasedViewHelper

Many view helpers output an HTML tag - for example <f:link.action ...> outputs a <a href="..."> tag. There are many ViewHelpers which work that way.

Very often, you want to add a CSS class or a target attribute to an <a href="..."> tag. This often leads to repetitive code like below. (Don’t look at the code too thoroughly, it should just demonstrate the boring and repetitive task one would have without the AbstractTagBasedViewHelper):

class ActionViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper {

  public function initializeArguments() {
        $this->registerArgument('class', 'string', 'CSS class to add to the link');
        $this->registerArgument('target', 'string', 'Target for the link');
        ... and more ...
  }

  public function render() {
        $output = '<a href="..."';
        if ($this->arguments['class']) {
          $output .= ' class="' . $this->arguments['class'] . '"';
        }
        if ($this->arguments['target']) {
          $output .= ' target="' . $this->arguments['target'] . '"';
        }
        $output .= '>';
        ... and more ...
        return $output;
  }

}

Now, the AbstractTagBasedViewHelper introduces two more methods you can use inside initializeArguments():

  • registerTagAttribute($name, $type, $description, $required): Use this method to register an attribute which should be directly added to the tag.
  • registerUniversalTagAttributes(): If called, registers the standard HTML attributes class, id, dir, lang, style, title.

Inside the AbstractTagBasedViewHelper, there is a TagBuilder available (with $this->tag) which makes building a tag a lot more straightforward.

With the above methods, the Link\ActionViewHelper from above can be condensed as follows:

class ActionViewHelper extends \TYPO3\\F3\Fluid\Core\AbstractViewHelper {

        public function initializeArguments() {
                $this->registerUniversalTagAttributes();
        }

        /**
         * Render the link.
         *
         * @param string $action Target action
         * @param array $arguments Arguments
         * @param string $controller Target controller. If NULL current controllerName is used
         * @param string $package Target package. if NULL current package is used
         * @param string $subpackage Target subpackage. if NULL current subpackage is used
         * @param string $section The anchor to be added to the URI
         * @return string The rendered link
         */
        public function render($action = NULL, array $arguments = array(),
                               $controller = NULL, $package = NULL, $subpackage = NULL,
                                   $section = '') {
                $uriBuilder = $this->controllerContext->getURIBuilder();
                $uri = $uriBuilder->uriFor($action, $arguments, $controller, $package, $subpackage, $section);
                $this->tag->addAttribute('href', $uri);
                $this->tag->setContent($this->renderChildren());

                return $this->tag->render();
        }

}

Additionally, we now already have support for all universal HTML attributes.

Tip

The TagBuilder also makes sure that all attributes are escaped properly, so to decrease the risk of Cross-Site Scripting attacks, make sure to use it when building tags.

additionalAttributes

Sometimes, you need some HTML attributes which are not part of the standard. As an example: If you use the Dojo JavaScript framework, using these non-standard attributes makes life a lot easier.

We think that the templating framework should not constrain the user in his possibilities – thus, it should be possible to add custom HTML attributes as well, if they are needed. Our solution looks as follows:

Every view helper which inherits from AbstractTagBasedViewHelper has a special argument called additionalAttributes which allows you to add arbitrary HTML attributes to the tag.

If the link tag from above needed a new attribute called fadeDuration, which is not part of HTML, you could do that as follows:

<f:link.action ... additionalAttributes="{fadeDuration : 800}">
        Link with fadeDuration set
</f:link.action>

This attribute is available in all tags that inherit from TYPO3\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper.

AbstractConditionViewHelper

If you want to build some kind of if/else condition, you should base the ViewHelper on the AbstractConditionViewHelper, as it gives you convenient methods to render the then or else parts of a ViewHelper. Let’s look at the <f:if>-ViewHelper for a usage example, which should be quite self-explanatory:

class IfViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractConditionViewHelper {

        /**
         * renders <f:then> child if $condition is true, otherwise renders <f:else> child.
         *
         * @param boolean $condition View helper condition
         * @return string the rendered string
         */
        public function render($condition) {
                if ($condition) {
                        return $this->renderThenChild();
                } else {
                        return $this->renderElseChild();
                }
        }

}

By basing your condition ViewHelper on the AbstractConditionViewHelper, you will get the following features:

  • Two API methods renderThenChild() and renderElseChild(), which should be used in the then / else case.
  • The ViewHelper will have two arguments defined, called then and else, which are very helpful in the Inline Notation.
  • The ViewHelper will automatically work with the <f:then> and <f:else>-Tags.
Widgets

Widgets are special ViewHelpers which encapsulate complex functionality. It can be best understood what widgets are by giving some examples:

  • <f:widget.paginate> renders a paginator, i.e. can be used to display large amounts of objects. This is best known from search engine result pages.
  • <f:widget.autocomplete> adds autocompletion functionality to a text field.
  • More widgets could include a Google Maps widget, a sortable grid, …

Internally, widgets consist of an own Controller and View.

Using Widgets

Using widgets inside your templates is really simple: Just use them like standard ViewHelpers, and consult their documentation for usage examples. An example for the <f:widget.paginate> follows below:

<f:widget.paginate objects="{blogs}" as="paginatedBlogs" configuration="{itemsPerPage: 10}">
  // use {paginatedBlogs} as you used {blogs} before, most certainly inside
  // a <f:for> loop.
</f:widget.paginate>

In the above example, it looks like {blogs} contains all Blog objects, thus you might wonder if all objects were fetched from the database. However, the blogs are not fetched from the database until you actually use them, so the Paginate Widget will adjust the query sent to the database and receive only the small subset of objects.

So, there is no negative performance overhead in using the Paginate Widget.

Writing widgets

We already mentioned that a widget consists of a controller and a view, all triggered by a ViewHelper. We’ll now explain these different components one after each other, explaining the API you have available for creating your own widgets.

ViewHelper

All widgets inherit from TYPO3\Fluid\Core\Widget\AbstractWidgetViewHelper. The ViewHelper of the widget is the main entry point; it controls the widget and sets necessary configuration for the widget.

To implement your own widget, the following things need to be done:

  • The controller of the widget needs to be injected into the $controller property.
  • Inside the render()-method, you should call $this->initiateSubRequest(), which will initiate a request to the controller which is set in the $controller property, and return the Response object.
  • By default, all ViewHelper arguments are stored as Widget Configuration, and are also available inside the Widget Controller. However, to modify the Widget Configuration, you can override the getWidgetConfiguration() method and return the configuration which you need there.

There is also a property $ajaxWidget, which we will explain later in Ajax Widgets.

Controller

A widget contains one controller, which must inherit from TYPO3\Fluid\Core\Widget\AbstractWidgetController, which is an ActionController. There is only one difference between the normal ActionController and the AbstractWidgetController: There is a property $widgetConfiguration, containing the widget’s configuration which was set in the ViewHelper.

Fluid Template

The Fluid templates of a widget are normal Fluid templates as you know them, but have a few ViewHelpers available additionally:

<f:uri.widget>
Generates an URI to another action of the widget.
<f:link.widget>
Generates a link to another action of the widget.
<f:renderChildren>
Can be used to render the child nodes of the Widget ViewHelper, possibly with some more variables declared.
Ajax Widgets

Widgets have special support for AJAX functionality. We’ll first explain what needs to be done to create an AJAX compatible widget, and then explain it with an example.

To make a widget AJAX-aware, you need to do the following:

  • Set $ajaxWidget to TRUE inside the ViewHelper. This will generate an unique AJAX Identifier for the Widget, and store the WidgetConfiguration in the user’s session on the server.

  • Inside the index-action of the Widget Controller, generate the JavaScript which triggers the AJAX functionality. There, you will need a URI which returns the AJAX response. For that, use the following ViewHelper inside the template:

    <f:uri.widget ajax="TRUE" action="..." arguments="..." />
    
  • Inside the template of the AJAX request, <f:renderChildren> is not available, because the child nodes of the Widget ViewHelper are not accessible there.

XSD schema generation

A XSD schema file for your ViewHelpers can be created by executing

./flow documenation:generatexsd <Your>\\<Package>\\ViewHelpers
        --target-file /some/directory/your.package.xsd

Then import the XSD file in your favorite IDE and map it to the namespace http://typo3.org/ns/<Your/Package>/ViewHelpers. Add the namespace to your Fluid template by adding the xmlns attribute to the root tag (usually <xml …> or <html …>).

Note

You are able to use a different XML namespace pattern by specifying the -–xsd-namespace argument in the generatexsd command.

If you want to use this inside partials, you can use the “section” argument of the render ViewHelper in order to only render the content of the partial.

Partial:

<html xmlns:x=”http://typo3.org/ns/Your/Package/ViewHelpers”>
<f:section name=”content”>
        <x:yourViewHelper />
</f:section>

Template:

<f:render partial=”PartialName” section=”content” />

Rendering A Page

This section shows how content is rendered on a page as a rough overview.

More precisely we show how to render a TYPO3.Neos:Document node, as everything which happens here works for all Document nodes, and not just for Page nodes.

First, the requested URL is resolved to a Node of type TYPO3.Neos:Document. This happens by translating the URL path to a node path, and finding the node with this path then.

The node is passed straight away to TypoScript, which is the rendering mechanism. TypoScript renders the node by traversing to sub-nodes and rendering them as well. The arguments which are passed to TypoScript are stored inside the so-called context, which contains all variables which are accessible by the TypoScript rendering engine.

Internally, TypoScript then asks Fluid to render certain snippets of the page, which can, in turn, ask TypoScript again. This can go back and forth multiple times, even recursively.

The Page TypoScript Object and -Template

The rendering of a page by default starts at a Case matcher at the TypoScript path root, which will usually select the TypoScript path page. The minimally needed TypoScript for rendering looks as follows:

page = Page
page.body.templatePath = 'resource://My.Package/Private/Templates/PageTemplate.html'

Here, the Page TypoScript object is assigned to the path page, telling the system that the TypoScript object Page is responsible for further rendering. Page expects one parameter to be set: The path of the Fluid template which is rendered inside the <body> of the resulting HTML page.

If this is an empty file, the output shows how minimal Neos impacts the generated markup:

<!DOCTYPE html>
<html version="HTML+RDFa 1.1"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:typo3="http://www.typo3.org/ns/2012/Flow/Packages/Neos/Content/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    >
  <!--
    This website is powered by Neos, the next generation CMS, a free Open
    Source Enterprise Content Management System licensed under the GNU/GPL.

    Neos is based on Flow, a powerful PHP application framework licensed under the GNU/LGPL.

    More information and contribution opportunities at http://neos.typo3.org and http://flow.typo3.org
  -->
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <script src="/_Resources/Static/Packages/TYPO3.Neos/JavaScript/LastVisitedNode.js" data-neos-node="a319a653-ef38-448d-9d19-0894299068aa"></script>
  </body>
</html>

It becomes clear that Neos gives as much control over the markup as possible to the integrator: No body markup, no styles, only little Javascript to record the last visited page (to redirect back to it after logging in). Except for the charset meta tag nothing related to the content is output by default.

If the template is filled with the following content:

<h1>{title}</h1>

the body would contain a heading to output the title of the current page:

<body>
        <h1>My first page</h1>
</body>

Again, no added CSS classes, no wraps. Why {title} outputs the page title will be covered in detail later.

Of course the current template is still quite boring; it does not show any content or any menu. In order to change that, the Fluid template is adjusted as follows:

{namespace ts=TYPO3\TypoScript\ViewHelpers}
{parts.menu -> f:format.raw()}
<h1>{title}</h1>
{content.main -> f:format.raw()}

Placeholders for the menu and the content have been added. Because the parts.menu and content.main refer to a rendered TypoScript path, the output needs to be passed through the f:format.raw() ViewHelper. The TypoScript needs to be adjusted as well:

page = Page
page.body {
        templatePath = 'resource://My.Package/Private/Templates/PageTemplate.html'

        parts.menu = Menu
        content.main = PrimaryContent {
                nodePath = 'main'
        }
}

In the above TypoScript, a TypoScript object at page.body.parts.menu is defined to be of type Menu. It is exactly this TypoScript object which is rendered, by specifying its relative path inside {parts.menu -> f:format.raw()}.

Furthermore, the PrimaryContent TypoScript object is used to render a TYPO3CR ContentCollection node. Through the nodePath property, the name of the TYPO3CR ContentCollection node to render is specified.

As a result, the web page now contains a menu and the contents of the main content collection.

The use of content and parts here is simply a convention, the names can be chosen freely. In the example content is used for anything that content is later placed in but parts is for anything that is not content in the sense that it will directly be edited in the content module of Neos.

Further Reading

Details on how TypoScript works and can be used can be found in the section Inside TypoScript. Adjusting Neos Output shows how page, menu and content markup can be adjusted freely.

Creating Custom Content Elements

Neos ships with commonly used, predefined content elements, but it is easily possible to amend and even completely replace them.

Defining new content elements is usually a three-step process:

  1. Defining a TYPO3CR Node Type, listing the properties and types of the node.
  2. Defining a TypoScript object which is responsible for rendering this content type. Usually, this is a wrapper for a Fluid Template which then defines the rendered markup.
  3. Add a Fluid Template which contains the markup being rendered
Creating a Simple Content Element

The following example creates a new content element Acme.Demo:YouTube which needs the YouTube URL and then renders the video player.

First, the TYPO3CR Node Type needs to be defined in NodeTypes.yaml. This can be done in your site package or in a package dedicated to content elements, if reuse is foreseeable.

'Acme.Demo:YouTube':
  superTypes:
   'TYPO3.Neos:Content': TRUE
  ui:
    group: 'general'
    label: 'YouTube Video'
    inspector:
      groups:
        video:
          label: 'Video'
          icon: 'icon-film'
  properties:
    videoUrl:
      type: string
      ui:
        label: 'Video URL'
        reloadIfChanged: TRUE
        inspector:
          group: 'video'

The declaration of node types with all required and optional properties is documented in Node Type Definition.

Next the TypoScript rendering for the content element has to be defined. By convention, a TypoScript object with the same name as the content element is used for rendering; thus in this case a TypoScript object My.Package:YouTube:

prototype(Acme.Demo:YouTube) < prototype(TYPO3.Neos:Content) {
        templatePath = 'resource://Acme.Demo/Private/Templates/TypoScriptObjects/YouTube.html'
        videoUrl = ${q(node).property('videoUrl')}
        width = '640'
        height = '360'
}

A new TypoScript object prototype with the name My.Package:YouTube is declared, inheriting from the pre-defined Template TypoScript object which provides rendering through Fluid.

The templatePath property of the YouTube TypoScript object is set to point to the Fluid template to use for rendering. All (other) properties which are set on the Template TypoScript object are directly made available inside Fluid as variables – and because the YouTube TypoScript object extends the Template TypoScript object, this rule also applies there.

Thus, the last line defines a videoUrl variable to be available inside Fluid, which is set to the result of the Eel expression ${q(node).property(‘videoUrl’)}. Eel is explained in depth in Eel, FlowQuery and Fizzle, but this is a close look at the used expression q(node).property(‘videoUrl’):

  • The q() function wraps its argument, in this case the TYPO3CR Node which is currently rendered, into FlowQuery.
  • FlowQuery defines the property(…) operation used to access the property of a node.

To sum it up: The expression ${q(node).property(‘videoUrl’)} is an Eel expression, in which FlowQuery is called to return the property videoUrl of the current node.

The final step in creating the YouTube content element is defining the YouTube.html Fluid template, f.e. with the following content:

<iframe width="{width}" height="{height}" src="{videoUrl}" frameborder="0" allowfullscreen></iframe>

In the template the {videoUrl} variable which has been defined in TypoScript is used as we need it.

What are the benefits of indirection through TypoScript?

In the above example the videoUrl property of the Node is not directly rendered inside the Fluid template. Instead TypoScript is used to pass the videoUrl from the Node into the Fluid template.

While this indirection might look superfluous at first sight, it has important benefits:

  • The Fluid Template does not need to know anything about Nodes. It just needs to know that it outputs a certain property, but not where it came from.

  • Because the rendering is decoupled from the data storage this way, the TypoScript object can be instantiated directly, manually setting a videoUrl:

    page.body.parts.teaserVideo = My.Package:YouTube {
      videoUrl = 'http://youtube.com/.....'
    }
    
  • If a property needs to be modified just slightly, a processor can be used for declarative modification of this property in TypoScript; not even touching the Fluid template. This is helpful for smaller adjustments to foreign packages.

Creating Editable Content Elements

The simple content element created in Creating a Simple Content Element exposes the video URL only through the property inspector in the editing interface. Since the URL is not directly visible this is the only viable way.

In case of content that is directly visible in the output, inline editing can be enabled by slight adjustments to the process already explained.

The node type definition must define which properties are inline editable through setting the inlineEditable property:

'Acme.Demo:Quote':
  superTypes:
    'TYPO3.Neos:Content': TRUE
  ui:
    group: 'general'
    label: 'Quote'
  properties:
    quote:
      type: string
      defaultValue: 'Use the force, Luke!'
      ui:
        label: 'Quote'
        inlineEditable: TRUE

The TypoScript for the content element is the same as for a non-inline-editable content element:

prototype(Acme.Demo:Quote) < prototype(TYPO3.Neos:Content) {
        templatePath = 'resource://Acme.Demo/Private/Templates/TypoScriptObjects/Quote.html'
        quote = ${q(node).property('quote')}
}

The Fluid template again needs some small adjustment in form of the contentElement.editable ViewHelper to declare the property that is editable. This may seem like duplication, since the node type already declares the editable properties. But since in a template multiple editable properties might be used, this still is needed.

{namespace neos=TYPO3\Neos\ViewHelpers}
<blockquote>
        {neos:contentElement.editable(property: 'quote')}
</blockquote>

The blockquote is wrapped around the contentElement.editable and not the other way because that would mean the blockquote becomes a part of the editable content, which is not desired in this case.

Using the tag attribute to make the ViewHelper use the blockquote tag needed for the element avoids the nesting in an additional container div and thus cleans up the generated markup:

{namespace neos=TYPO3\Neos\ViewHelpers}
{neos:contentElement.editable(property: 'quote', tag: 'blockquote')}

A property can be inline editable and appear in the property inspector if configured accordingly. In such a case reloadIfChanged should be enabled to make changes in the property editor visible in the content area.

Creating Nested Content Elements

In case content elements do not only contain simple properties, but arbitrary sub-elements, the process again is roughly the same. To demonstrate this, a Video Grid content element will be created, which can contain two texts and two videos.

  1. A TYPO3CR Node Type definition is created. It makes use of the childNodes property to define (and automatically create) sub-nodes when a node of this type is created. In the example the two video and text elements will be created directly upon element creation:

    'Acme.Demo:VideoGrid':
      superTypes:
        'TYPO3.Neos:Content': TRUE
      ui:
        group: 'structure'
        label: 'Video Grid'
      childNodes:
        video0:
          type: 'Acme.Demo:YouTube'
        video1:
          type: 'Acme.Demo:YouTube'
        text0:
          type: 'TYPO3.Neos.NodeTypes:Text'
        text1:
          type: 'TYPO3.Neos.NodeTypes:Text'
    
  2. The needed TypoScript is created:

    prototype(Acme.Demo:VideoGrid) {
            videoRenderer = Acme.Demo:YouTube
            textRenderer = TYPO3.Neos.NodeTypes:Text
    
            video0 = ${q(node).children('video0').get(0)}
            video1 = ${q(node).children('video1').get(0)}
    
            text0 = ${q(node).children('text0').get(0)}
            text1 = ${q(node).children('text1').get(0)}
    }
    

    Instead of assigning variables to the Fluid template, additional TypoScript objects responsible for the video and the text rendering are instantiated. Furthermore, the video and text nodes are fetched using Eel and then passed to the Fluid template.

  3. The Fluid template is created. Instead of outputting the content directly using object access on the passed nodes, the <ts:render> ViewHelper is used to defer rendering to TypoScript again. The needed TYPO3CR Node is passed as context to TypoScript:

    {namespace ts=TYPO3\TypoScript\ViewHelpers}
    <ts:render path="videoRenderer" context="{node: video0}" />
    <ts:render path="textRenderer" context="{node: text0}" />
    <br />
    <ts:render path="videoRenderer" context="{node: video1}" />
    <ts:render path="textRenderer" context="{node: text1}" />
    

Instead of referencing specific content types directly the use of the generic ContentCollection content element allows to insert arbitrary content inside other elements. An example can be found in the TYPO3.Neos.NodeTypes:MultiColumn and TYPO3.Neos.NodeTypes:MultiColumnItem content elements.

As explained earlier (in What are the benefits of indirection through TypoScript?) the major benefit if using TypoScript to decouple the rendering of items this way is flexibility. In the video grid it shows how this enables composability, other TypoScript objects can be re-used for rendering smaller parts of the element.

Content Element Group

In Neos content elements are grouped by type. By default the following groups are available:

general
Basic content elements, like text and image.
structure
Elements defining a structure. This group contains for example the 2 column element.
plugins
Available plugins in the site installation.

It is possible to create new groups by using the TYPO3.Neos.nodeTypes.groups settings. Registering 2 new groups could look like:

TYPO3:
  Neos:
    nodeTypes:
      groups:
        form:
          label: 'Form elements'
        special:
          position: 50
          label: 'Special elements'
          collapsed: true
          icon: 'icon-fort-awesome'

The groups are ordered by the position argument.

Extending The Inspector

Warning

Adding editors and validators is no fixed API yet, keep an eye on the changelogs if you use this.

It is possible to extend the inspector for adding new editors and validators to edit the properties of your nodetypes.

Editors

By default the following list of editors is available in Neos:

  • TYPO3.Neos/Inspector/Editors/BooleanEditor

    A checkbox, by default configured for properties of type boolean.

  • TYPO3.Neos/Inspector/Editors/DateTimeEditor

    A datepicker with support for time selection too. By default configured for properties of type date.

  • TYPO3.Neos/Inspector/Editors/CodeEditor

    An code editor with syntax highlighting. You can use this editor for editing other types of textual content, by configuring a different highlightingMode and buttonLabel to change usage for this editor:

    style:
      type: string
      ui:
        label: 'CSS'
        reloadIfChanged: TRUE
        inspector:
          group: 'code'
          editor: 'TYPO3.Neos/Inspector/Editors/CodeEditor'
          editorOptions:
            buttonLabel: 'Edit CSS source'
            highlightingMode: 'text/css'
    
  • TYPO3.Neos/Inspector/Editors/ImageEditor

    An image editor with cropping and size support. By default configured for properties of type TYPO3MediaDomainModelImageInterface.

  • TYPO3.Neos/Inspector/Editors/ReferenceEditor

    A selector with autocomplete to reference to another node. By default configured for properties of type reference.

  • TYPO3.Neos/Inspector/Editors/ReferencesEditor

    A selector with autocomplete to reference to multiple nodes. By default configured for properties of type references.

  • TYPO3.Neos/Inspector/Editors/SelectBoxEditor

    A selectbox.

  • TYPO3.Neos/Inspector/Editors/TextFieldEditor

    A simple textfield. By default configured for properties of type string and integer

The following editors are also available, but will most likely only be used internally in Neos:

  • TYPO3.Neos/Inspector/Editors/MasterPluginEditor
  • TYPO3.Neos/Inspector/Editors/PluginViewEditor
  • TYPO3.Neos/Inspector/Editors/PluginViewsEditor
Register Custom Editors

There are 2 ways to register custom editors. Either by registering a namespace for a group of editors, or by selecting the direct path to an editor specifically.

Registering a namespace pointing to a folder containing editors works as follows:

  • Create a folder containing the JavaScript sources for the editors

  • Name your files PropertyTypeEditor

  • Configure the path as a requirejs path mapping using the following Settings.yaml

    TYPO3:
      Neos:
        userInterface:
          requireJsPathMapping:
            'My.Package/Inspector/Editors': 'resource://My.Package/Public/Scripts/Path/To/Folder'
    
  • Now configure the editor for your property in the NodeTypes.yaml:

    'My.Package:NodeType':
      properties:
        myProperty:
          type: 'string'
          ui:
            inspector:
              editor: 'My.Package/Inspector/Editors/PropertyTypeEditor'
              editorOptions:
                optionName: 'optionValue'
    

To set global options for your editor you can set a set of defaults in Settings.yaml:

TYPO3:
  Neos:
    userInterface:
      inspector:
        editors:
          'My.Package/Inspector/Editors/PropertyTypeEditor':
            editorOptions:
              optionName: 'optionValue'

The editor options set on a property level will override the global editor options.

To register just one specific path as an editor use the following code:

TYPO3:
  Neos:
    userInterface:
      inspector:
        editors:
          'My.Package/Inspector/Editors/CustomEditor':
            path: 'resource://My.Package/Public/Scripts/Path/To/File/Without/Js/Extension'
Validators

By default the following validators are available in Neos:

  • TYPO3.Neos/Validation/AbstractValidator

    This abstract validator should be used to base custom validators on.

  • TYPO3.Neos/Validation/AlphanumericValidator

    Supported options:

    • regularExpression
  • TYPO3.Neos/Validation/CountValidator

    Supported options:

    • minimum
    • maximum
  • TYPO3.Neos/Validation/DateTimeRangeValidator

    Supported options:

    • latestDate
    • earliestDate
  • TYPO3.Neos/Validation/DateTimeValidator

  • TYPO3.Neos/Validation/EmailAddressValidator

    Supported options:

    • regularExpression
  • TYPO3.Neos/Validation/FloatValidator

  • TYPO3.Neos/Validation/IntegerValidator

  • TYPO3.Neos/Validation/LabelValidator

    Supported options:

    • regularExpression
  • TYPO3.Neos/Validation/NumberRangeValidator

    Supported options:

    • minimum
    • maximum
  • TYPO3.Neos/Validation/RegularExpressionValidator

    Supported options:

    • regularExpression
  • TYPO3.Neos/Validation/StringLengthValidator

    Supported options:

    • minimum
    • maximum
  • TYPO3.Neos/Validation/StringValidator

  • TYPO3.Neos/Validation/TextValidator

  • TYPO3.Neos/Validation/UuidValidator

    Supported options:

    • regularExpression
Register Custom Validators

There are 2 ways to register custom validators. Either by registering a namespace for a group of validators, or by selecting the direct path to an validator specifically.

Registering a namespace pointing to a folder containing validators works as follows:

  • Create a folder containing the JavaScript sources for the validators

  • Name your files DataTypeValidator

  • Configure the path as a requirejs path mapping using the following Settings.yaml

    TYPO3:
      Neos:
        userInterface:
          requireJsPathMapping:
            'My.Package/Validation': 'resource://My.Package/Public/Scripts/Path/To/Folder'
    
  • Now configure the validator for your property in the NodeTypes.yaml:

    'My.Package:NodeType':
      properties:
        myProperty:
          type: 'string'
          validation:
            'My.Package/Validation/DataTypeValidator': []
    

To register just one specific path as a validator use the following code:

TYPO3:
  Neos:
    userInterface:
      validators:
        'My.Package/Validation/CustomValidator':
          path: 'resource://My.Package/Public/Scripts/Path/To/File/Without/Js/Extension'

Adjusting Neos Output

Page Template

The page template defines the overall structure of the generated markup: what is rendered in the body and head of the resulting document.

The Body

As briefly explained in Rendering A Page the path to your own template for the body of a generated page can be set using TypoScript:

page = Page
page.body.templatePath = 'resource://My.Package/Private/Templates/PageTemplate.html'

The file will the be used to render the body content and any Fluid placeholders will be substituted, ViewHelpers will be executed. Since no further information is given to the rendering process, the full content of the template will be used for the body.

If the template contains a full HTML page, this will lead to invalid markup. But in most cases having the template as a full HTML document is desired, as it allows easy handling by the developer and can be previewed as is in a browser.

To use just a part of the document for the body, that part can simply be enclosed in a Fluid section:

<!DOCTYPE html>
<html>
<head>
        
</head>
<body>
<f:section name="body">
        <h1>{title}</h1>
</f:section>
</body>
</html>

The TypoScript is then amended with the declaration of the section to use:

page = Page
page.body {
        templatePath = 'resource://My.Package/Private/Templates/PageTemplate.html'
        sectionName = 'body'
}

This results in only the part inside the template’s “body” section to be used for rendering the body of the generated page.

To add actual content from Neos to the desired places in the markup, a special ViewHelper to turn control back to TypoScript is used. This has been mentioned in Rendering A Page already.

This template uses the render ViewHelper twice, once to render the path parts/menu and once to render the path content.main:

<f:section name="body">
        <ts:render path="parts.menu" />
        <h1>{title}</h1>
        <ts:render path="content.main" />
</f:section>

Those paths are relative to the current path. Since that part of the template is rendered by the TypoScript object at page.body, this is the starting point for the relative paths. This means the Menu and the ContentCollection in this TypoScript are used for rendering the output:

page = Page
page.body {
        templatePath = 'resource://My.Package/Private/Templates/PageTemplate.html'
        sectionName = 'body'
        parts.menu = Menu
        content.main = ContentCollection
        content.main.nodePath = 'main'
}
The Head

The head of a page generated by Neos contains only minimal content by default. Apart from the meta tag declaring the character set it is empty:

<head>
        <meta charset="UTF-8" />
</head>

To fill this with life, it is recommended to add sections to the head of your HTML template that group the needed parts. Additional TypoScript Template objects are then used to include them into the generated page. Here is an example:

Page/Default.html

<head>
        <f:section name="meta">
                <title>{title}</title>
        </f:section>

        <f:section name="stylesheets">
                <!-- put your stylesheet inclusions here, they will be included in your website by TypoScript -->
        </f:section>

        <f:section name="scripts">
                <!-- put your javascript inclusions here, they will be included in your website by TypoScript -->
        </f:section>
</head>

Library/Root.ts2

page.head {
        meta = TYPO3.TypoScript:Template {
                templatePath = 'resource://Acme.DemoCom/Private/Templates/Page/Default.html'
                sectionName = 'meta'

                title = ${q(node).property('title')}
        }
        stylesheets.site = TYPO3.TypoScript:Template {
                templatePath = 'resource://Acme.DemoCom/Private/Templates/Page/Default.html'
                sectionName = 'stylesheets'
        }
        javascripts.site = TYPO3.TypoScript:Template {
                templatePath = 'resource://Acme.DemoCom/Private/Templates/Page/Default.html'
                sectionName = 'scripts'
        }
}

The TypoScript fills the page.head instance of TYPO3.TypoScript:Array with content. The predefined paths for page.head.stylesheets, page.head.javascripts or page.body.javascripts should be used to add custom includes. They are implemented by a TypoScript Array and allow arbitrary items to specify JavaScript or CSS includes without any restriction on the content.

This will render some more head content:

        <head>
        
        <title>Home</title>
        <!-- put your stylesheet inclusions here, they will be included in your website by TypoScript -->
        <!-- put your javascript inclusions here, they will be included in your website by TypoScript -->
        
</head>

This provides for flexibility and allows to control precisely what ends up in the generated markup. Anything that is needed can be added freely, it just has to be in a section that is included.

Content Element Rendering

The rendering of content elements follows the same principle as shown for the Menu. The default TypoScript is defined in the Neos.NodeTypes package and the content elements all have default Fluid templates.

Combined with the possibility to define custom templates per instance or on the prototype level, this already provides a lot of flexibility. Another possibility is to inherit from the existing TypoScript and adjust as needed using TypoScript.

The available properties and settings that the TypoScript objects in Neos provide are described in TypoScript Reference.

Including CSS and JavaScript in a Neos Site

Including CSS and JavaScript should happen through one of the predefined places of the Page object. Depending on the desired position one of the page.head.javascripts, page.head.stylesheets or page.body.javascripts Arrays should be extended with an item that renders script or stylesheet includes:

page.head {

        stylesheets {
                bootstrap = '<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">'
        }

        javascripts {
                jquery = '<script src="//code.jquery.com/jquery-1.10.1.min.js"></script>'
        }

}

page.body {

        javascripts {
                bootstrap = '<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>'
        }

}

The page.body.javascripts content will be appended to the rendered page template so the included scripts should be placed before the closing body tag. As always in TypoScript the elements can be a simple string value, a TypoScript object like Template or an expression:

page.head {
        # Add a simple value as an item to the javascripts Array
        javascripts.jquery = '<script src="//code.jquery.com/jquery-1.10.1.min.js"></script>'

        # Use an expression to render a CSS include (this is just an example, bootstrapVersion is not defined by Neos)
        stylesheets.bootstrap = ${'<link href="//netdna.bootstrapcdn.com/bootstrap/' + bootstrapVersion + '/css/bootstrap.min.css" rel="stylesheet">'}
}

page.body {
        # Use a Template object to access a special section of the site template
        javascripts.site = TYPO3.TypoScript:Template {
                templatePath = 'resource://Acme.DemoCom/Private/Templates/Page/Default.html'
                sectionName = 'bodyScripts'
        }
}

The order of the includes can be specified with the @position property inside the Array object. This is especially handy for including JavaScript libraries and plugins in the correct order:

page.head {
        jquery = '<script src="//code.jquery.com/jquery-1.10.1.min.js"></script>'

        javascripts.jquery-ui = '<script src="path-to-jquery-ui"></script>'
        javascripts.jquery-ui.@position = 'after jquery'
}
CSS and JavaScript restrictions in a Neos Site

Very little constraints are imposed through Neos for including JavaScripts or stylesheets. But since the Neos user interface itself is built with HTML, CSS and JavaScript itself, some caveats exist.

Since the generated markup contains no stylesheets by default and the generated JS is minimal, those restrictions affect only the display of the page to the editor when logged in to the Neos editing interface.

In this case, the Neos styles are included and a number of JavaScript libraries are loaded, among them jQuery, Ember JS and VIE. The styles are all confined to a single root selector and for JavaScript the impact is kept as low as possible through careful scoping.

CSS Requirements
  • the <body> tag is not allowed to have a CSS style with position:relative, as this breaks the positions of modal dialogs we show at various places. Zurb Foundation is one well-known framework which sets this as default, so if you use it, then fix the error with body { position: static }.

TODO check if this is still true

JavaScript Requirements

TODO “what about the UI below a single DOM element idea”

Adjusting the HTTP response

It is possible to set HTTP headers and the status code of the response from TypoScript. See TYPO3.TypoScript:Http.Message for an example.

Content Dimensions

Introduction

Content dimensions are a generic concept to have multiple variants of a node. A dimension can be anything like “language”, “country” or “customer segment”. The content repository supports any number of dimensions. Node variants can have multiple values for each dimension and are connected by the same identifier. This enables a single-tree approach for localization, personalization or other variations of the content in a site.

If content is rendered and thus fetched from the content repository, it will always happen in a context. This context contains a list of values for each dimension that specifies which dimension values are visible and in which fallback order these should apply. So the same node variants can yield different results depending on the context that is used to fetch the nodes.

Dimension presets assign a name to the list of dimension values and are used to display dimensions in the user interface or in the routing. They represent the allowed combinations of dimension values.

Tip

See the Translating content cookbook for a step-by-step guide to create a multi-lingual website with Neos.

Dimension Configuration

The available dimensions and presets can be configured via settings:

TYPO3:
  TYPO3CR:
    contentDimensions:

      # Content dimension "language" serves for translation of content into different languages. Its value specifies
      # the language or language variant by means of a locale.
      'language':
        # The default dimension that is applied when creating nodes without specifying a dimension
        default: 'mul_ZZ'
        # The default preset to use if no URI segment was given when resolving languages in the router
        defaultPreset: 'all'
        label: 'Language'
        icon: 'icon-language'
        presets:
          'all':
            label: 'All languages'
            values: ['mul_ZZ']
            uriSegment: 'all'
          # Example for additional languages:

          'en_GB':
            label: 'English (Great Britain)'
            values: ['en_GB', 'en_ZZ', 'mul_ZZ']
            uriSegment: 'gb'
          'de':
            label: 'German (Germany)'
            values: ['de_DE', 'de_ZZ', 'mul_ZZ']
            uriSegment: 'de'

The TYPO3CR and Neos packages don’t provide any dimension configuration per default.

Preset Constraints

Neos can be configured to work with more than one content dimension. A typical use case is to define separate dimensions for language and country: pages with product descriptions may be available in English and German, but the English content needs to be different for the markets target to the UK or Germany respectively. However, not all possible combinations of language and country make sense and thus should not be accessible. The allowed combinations of content dimension presets can be controlled via the preset constraints feature.

Consider a website which has dedicated content for the US, Germany and France. The content for each country is available in English and their respective local language. The following configuration would make sure that the combinations “German – US”, “German - France”, “French - US” and “French - Germany” are not allowed:

TYPO3:
  TYPO3CR:
    contentDimensions:
      'language':
        default: 'en'
        defaultPreset: 'en'
        label: 'Language'
        icon: 'icon-language'
        presets:
          'en':
            label: 'English'
            values: ['en']
            uriSegment: 'en'
          'de':
            label: 'German'
            values: ['de']
            uriSegment: 'de'
            constraints:
              country:
                'us': false
                'fr': false
          'fr':
            label: 'French'
            values: ['fr']
            uriSegment: 'fr'
            constraints:
              country:
                'us': false
                'de': false
      'country':
        default: 'us'
        defaultPreset: 'us'
        label: 'Country'
        icon: 'icon-globe'
        presets:
          'us':
            label: 'United States'
            values: ['us']
            uriSegment: 'us'
          'de':
            label: 'Germany'
            values: ['de']
            uriSegment: 'de'
          'fr':
            label: 'France'
            values: ['fr']
            uriSegment: 'fr'

Instead of configuring every constraint preset explicitly, it is also possible to allow or disallow all presets of a given dimension by using the wildcard identifier. The following configuration has the same effect like in the previous example:

TYPO3:
  TYPO3CR:
    contentDimensions:
      'language':
        default: 'en'
        defaultPreset: 'en'
        label: 'Language'
        icon: 'icon-language'
        presets:
          'en':
            label: 'English'
            values: ['en']
            uriSegment: 'en'
          'de':
            label: 'German'
            values: ['de']
            uriSegment: 'de'
            constraints:
              country:
                'de': true
                '*': false
          'fr':
            label: 'French'
            values: ['fr']
            uriSegment: 'fr'
            constraints:
              country:
                'fr': true
                '*': false
      'country':
        default: 'us'
        defaultPreset: 'us'
        label: 'Country'
        icon: 'icon-globe'
        presets:
          'us':
            label: 'United States'
            values: ['us']
            uriSegment: 'us'
          'de':
            label: 'Germany'
            values: ['de']
            uriSegment: 'de'
          'fr':
            label: 'France'
            values: ['fr']
            uriSegment: 'fr'

While the examples only defined constraints in the language dimension configuration, it is perfectly possible to additionally or exclusively define constraints in country or other dimensions.

Migration of existing content

Adjusting content dimensions configuration can lead to issues for existing content. When a new content dimension is added, a corresponding value needs to be added to existing content, otherwise no nodes would be found.

This can be done with a node migration which is included in the TYPO3.TYPO3CR package:

./flow node:migrate 20150716212459

This migration adds missing content dimensions by setting the default value on all existing nodes, if not already set.

Alternatively a custom node migration can be created allowing flexibility and constraints. See Node Migration Reference.

Routing

Neos provides a route-part handler that will include a prefix with the value of the uriSegment setting of a dimension preset for all configured dimensions. This means URIs will not contain any prefix by default as long as no content dimension is configured. Multiple dimensions are joined with a _ character, so the uriSegment value must not include an underscore.

The default preset can have an empty uriSegment value. The following example will lead to URLs that do not contain en if the en_US preset is active, but will show the uriSegment for other languages that are defined as well:

TYPO3:
  TYPO3CR:
    contentDimensions:

      'language':
        default: 'en'
        defaultPreset: 'en_US'
        label: 'Language'
        icon: 'icon-language'
        presets:
          'en':
            label: 'English (US)'
            values: ['en_US']
            uriSegment: ''

The only limitation is that all segments must be unique across all dimensions. If you need non-unique segments, you can switch support for non-empty dimensions off:

TYPO3:
  Neos:
    routing:
      supportEmptySegmentForDimensions: FALSE

Limitations

In Neos 1.2 node variants can only be created by having a common fallback value in the presets. This means a node can only be translated to some other dimension value if it “shined” through from a fallback value.

In Neos 2.0, it is possible to create node variants across dimension borders, i.e. to translate an English version of a Document to German, without having fall-backs from German to English or vice versa.

Note

This is a documentation stub.

Multi Site Support

Separating Assets Between Sites

In multi-site setups it can become a use case to having to separate assets to a between sites. For this Neos supports creating asset collections. An asset collection can contain multiple assets, and an asset can belong to multiple collections. Additionally tags can belong to one or multiple collections.

Every site can (in the site management module) be configured to have a default asset collection. This means that when assets are uploaded in the inspector they will automatically be added to the sites collection if one is configured. When the editor opens the media browser/module it will automatically select the current sites collection.

The media browser/module allows administrators to create/edit/delete collections and also select which tags are included in a collection.

Content Cache

Introduction

The frontend rendering of a document node in Neos can involve many queries and operations. Doing this for every request would be too slow to achieve a feasible response time. The content cache is a feature of TypoScript and supports a configurable and nested cache that can answer many requests directly from the cache without expensive operations. It is based on the Flow caching framework that supports many different cache backends, expiration and tagging.

Each TypoScript path (of type object) can have its own cache configuration. These cache configurations can be nested to re-use parts of the content and have multiple cache entries with different properties on the same page. This could be a menu or section that is the same for many pages. The nesting support is also allows to have uncached content like plugins inside cached content.

The content cache is active even when you are in editing mode. Cache entries will be flushed automatically whenever data has changed through a tag based strategy or when relevant files changed during development (code, templates or configuration).

Note

In Neos, you don’t a have a button to clear the cache. Cache invalidation is handled by the core and can be configured to be application specific. It’s really important to configure the cache correctly to avoid problems with cache invalidation.

An example cache hierarchy

An example cache hierarchy with different modes

Let’s see how the content cache can help you to deliver a faster user experience.

The basics

The main TypoScript path is root, you can find it in the file TypoScript/DefaultTypoScript.ts2 in the TYPO3.Neos package. Here is a small part of this file that shows the outermost cache configuration of the root path:

root = TYPO3.TypoScript:Case {
        default {
                @position = 'end 9999'
                condition = TRUE
                renderPath = '/page'
        }

        @cache {
                mode = 'cached'

                maximumLifetime = '86400'

                entryIdentifier {
                        node = ${node}
                        editPreviewMode = ${node.context.currentRenderingMode.name}
                }

                entryTags {
                        # Whenever the node changes the matched condition could change
                        1 = ${'Node_' + documentNode.identifier}
                        # Whenever one of the parent nodes changes the layout could change
                        2 = ${'DescendantOf_' + documentNode.identifier}
                }
        }
}

The given configuration will cache the entire page content with a unique identifier defined by the current node (the document node), the preview mode and globally configured entry identifiers.

Note

All entryIdentifier values will be evaluated and combined to a single string value (the keys will be part of the identifier and sorted alphabetically).

In the @cache meta property the following subproperties are allowed:

mode

Sets the caching mode of the current path. Possible values are 'embed' (default), 'cached', 'dynamic' or 'uncached'. Only simple string values are supported for this property.

It defaults to mode embed which will not create a new cache entry but store the con`tent into the next outer cached entry. With mode cached a separate cache entry will be created for the path. Mode uncached can be used to always evaluate a path even if is contained inside a cached path. The dynamic mode evalutes a so called “discriminator” on every request and caches results differently depending on it’s value. Dynamic cache mode is therefore much faster than uncached but slightly slower compared to cached mode. It is useful in situations where arguments (eg. from the request) lead to different rendering results. The context property should be set to configure the TypoScript context variables that will be available when evaluating the uncached path.

maximumLifetime

Set the maximum lifetime for the nearest cached path. Possible values are null (default), 0 (unlimited lifetime) or the amount of seconds as an integer.

If this property is declared on a path with caching mode cached or dynamic it will set the lifetime of the cache entry to the minimum of all nested maximumLifetime configurations (in paths with mode embed) and the maximumLifetime of the current configuration.

entryIdentifier

Configure the cache entry identifier for mode cached or dynamic based on an array of values.

The prototype TYPO3.TypoScript:GlobalCacheIdentifiers will be used as the base object, so global values that influence all cache entries can be added to that prototype, see Global cache entry identifiers for more details.

If this property is not set, the identifier is built from all TypoScript context values that are simple values or implement CacheAwareInterface.

The identifier string value will be a hash built over all array values including and sorted by their key.

Note

It is very important to add all values that influence the output of the current path to the entryIdentifier array since cache entries will be re-used across rendered documents if the same identifier is requested. In the cache hierarchy the outermost cache entry determines all the nested entries, so it’s important to add values that influence the rendering for every cached path along the hierarchy.

entryTags

Configure a set of tags that will be assigned to the cache entry for mode cached or dynamic as an array.

The correct entry tags are important to achieve an automatic flushing of affected cache entries if a node or other data in Neos was changed during editing, publishing or other actions. A number of tags with a specific pattern are flushed by default in Neos whenever a node is changed, published or discarded. See Cache Entry Tags for a full list.

context

Configure a list of variable names that will be stored from the TypoScript context for later rendering of a path with mode uncached or dynamic. Only values that are configured here will be available in TypoScript when the path is evaluated in subsequent request.

Example from Plugin.ts2:

prototype(TYPO3.Neos:Plugin) {
        @cache {
                mode = 'uncached'
                context {
                        1 = 'node'
                        2 = 'documentNode'
                }
        }
}
entryDiscriminator

Configure an expression that uniquely discriminates different entries of a dynamic cached area. The expression or TypoScript object must evaluate to a string to be used as discriminator and should be different for every cache entry you want to create for this dynamic cached area.

Example for a dynamic configuration with entryDiscriminator:

prototype(TYPO3.Neos:Plugin) {
        @cache {
                mode = 'dynamic'
                entryIdentifier {
                  node = ${node}
                }
                entryDiscriminator = ${request.arguments.pagination}
                context {
                        1 = 'node'
                        2 = 'documentNode'
                }
                entryTags {
                        1 = ${'Node_' + node.identifier}
                }
        }
}

When using dynamic as the cache mode, the cache can be disabled by setting the entryDiscriminator to false. This can be used to make the cache behavior dependable on some context, i.e. the current request method:

prototype(TYPO3.Neos.NodeTypes:Form) {
        @cache {
                mode = 'dynamic'
                entryIdentifier {
                  node = ${node}
                }
                entryDiscriminator = ${request.httpRequest.methodSafe ? 'static' : false}
                context {
                        1 = 'node'
                        2 = 'documentNode'
                }
        }
}

In this example the Form will be cached unless the request method is unsafe (for example POST) in which case it is switched to uncached.

Cache Entry Tags

Neos will automatically flush a set of tags whenever nodes are created, changed, published or discarded. The exact set of tags depends on the node hierarchy and node type of the changed node. You should assign tags that mathches one of these patterns in your configuration. You can use an Eel expression to build the pattern depending on any context variable including the node identifier or type.

The following patterns of tags will be flushed by Neos:

Everything
Flushes cache entries for every changed node.
NodeType_[My.Package:NodeTypeName]
Flushes cache entries if any node with the given node type changes. [My.Package:NodeTypeName] needs to be replaced by any node type name. Inheritance will be taken into account, so for a changed node of type TYPO3.Neos.NodeTypes:Page the tags NodeType_TYPO3.Neos.NodeTypes:Page and NodeType_TYPO3.Neos:Document (and some more) will be flushed.
Node_[Identifier]
Flushes cache entries if a node with the given identifier changes. Identifier needs to be replaced by a valid node identifier.
DescendantOf_[Identifier]
Flushes cache entries if a child node of the node with the given identifier changes. Identifier need to be replaced by a valid node identifier.

Example:

prototype(TYPO3.Neos:ContentCollection) {
        #...

        @cache {
                #...

                entryTags {
                        1 = ${'Node_' + node.identifier}
                        2 = ${'DescendantOf_' + contentCollectionNode.identifier}
                }
        }
}

The ContentCollection cache configuration declares a tag that will flush the cache entry for the collection if any of it’s descendants (direct or indirect child) changes. So editing a node inside the collection will flush the whole collection cache entry and cause it to re-render.

Note

When using cached as the cache mode, your entryTags should always contain the node identifier. Otherwise, the cache will not be flushed when you make changes to the node itself, which will lead to unexpected behavior in the Neos backend:

@cache {
        mode = 'cached'
        entryTags {
                1 = ${'Node_' + node.identifier}
                2 = ... additional entry tags ...
        }
}

Default cache configuration

The following list of TypoScript prototypes is cached by default:

  • TYPO3.Neos:Breadcrumb
  • TYPO3.Neos:Menu
  • TYPO3.Neos:Page
  • TYPO3.Neos:ContentCollection (see note)

The following list of TypoScript prototypes is uncached by default:

  • TYPO3.Neos.NodeTypes:Form
  • TYPO3.Neos:Plugin

Note

The TYPO3.Neos:ContentCollection prototype is cached by default and has a cache configuration with proper identifier, tags and maximumLifetime defined. For all ContentCollection objects inside a Content object the mode is set to embed. This means that node types that have a ContentCollection do not generate a separate cache entry but are embedded in the outer static ContentCollection.

Overriding default cache configuration

You can override default cache configuration in your TypoScript:

prototype(TYPO3.Neos:PrimaryContent).@cache.mode = 'uncached'

You can also override cache configuration for a specific TypoScript Path:

page.body.content.main {
    prototype(TYPO3.Neos:Plugin).@cache.mode = 'cached'
}

Global cache entry identifiers

Information like the request format or base URI that was used to render a site might have impact on all generated URIs. Depending on the site or application other data might influence the uniqueness of cache entries. If an entryIdentifier for a cached path is declared without an object type, it will default to TYPO3.TypoScript:GlobalCacheIdentifiers:

prototype(My.Package:ExampleNode) {
        @cache {
                mode = 'cached'

                # This is the default if no object type is specified
                # entryIdentifier = TYPO3.TypoScript:GlobalCacheIdentifiers
                entryIdentifier {
                        someValue = ${q(node).property('someValue')}
                }
        }
}

This prototype can be extended to add or remove custom global values that influence all cache entries without a specific object type:

prototype(TYPO3.TypoScript:GlobalCacheIdentifiers) {
        myRequestArgument = ${request.arguments.myArgument}
}

You can use a TYPO3.TypoScript:RawArray to explicitly specify the values that are used for the entry identifier:

prototype(My.Package:ExampleNode) {
        @cache {
                mode = 'cached'

                entryIdentifier = TYPO3.TypoScript:RawArray {
                        someValue = ${q(node).property('someValue')}
                }
        }
}
Security Context

In addition to entry identifiers configured in Fusion, the Security Context Hash is added to the identifier of all cached segments. This hash is build from the roles of all authenticated accounts and cache identifiers from custom global objects (exposed through Neos.Flow.aop.globalObjects) implementing CacheAwareInterface. [1]

Tuning your cache

Change the cache backend

By default, all cache entries are stored on the local filesystem. You can change this in Caches.yaml, the example below will use the Redis backend for the content cache:

TYPO3_TypoScript_Content:
  backend: TYPO3\Flow\Cache\Backend\RedisBackend

Note

The best practice is to change the cache configuration in your distribution.


[1]Custom Global Objects are explained in detail in the Flow documentation: http://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/Security.html#content-security-entityprivilege.

Permissions & Access Management

Introduction

A common requirement, especially for larger websites with many editors, is the possibility to selectively control access to certain backend tools and parts of the content. For example so that editors can only edit certain pages or content types or that they are limited to specific workspaces. These access restrictions are used to enforce certain workflows and to reduce complexity for editors.

Neos provides a way to define Access Control Lists (ACL) in a very fine-grained manner, enabling the following use cases:

  • hide parts of the node tree completely (useful for multi-site websites and frontend-login)
  • show only specific Backend Modules
  • allow to create/edit only specific Node Types
  • allow to only edit parts of the Node Tree
  • allow to only edit a specific dimension

The underlying security features of Flow provide the following generic possibilities in addition:

  • protect arbitrary method calls
  • define the visibility of arbitrary elements depending on the authenticated user

Privilege targets define what is restricted, they are defined by combining privileges with matchers, to address specific parts of the node tree. A user is assigned to one or more specific roles, defining who the user is. For each role, a list of privileges is specified, defining the exact permissions of users assigned to each role.

In the Neos user interface, it is possible to assign a list of multiple roles to a user. This allows to define the permissions a user actually has on a fine-grained level. Additionally, the user management module has basic support for multiple accounts per user: a user may, for example, have one account for backend access and another one for access to a member-only area on the website.

As a quick example, a privilege target giving access to a specific part of the node tree looks as follows:

'TYPO3\TYPO3CR\Security\Authorization\Privilege\NodeTreePrivilege':
  'YourSite:EditWebsitePart':
    matcher: 'isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")'

Adjusting and defining roles

Neos comes with a number of predefined roles that can be assigned to users:

Role Parent role(s) Description
TYPO3.TYPO3CR:Administrator   A no-op role for future use
TYPO3.Neos:AbstractEditor TYPO3.TYPO3CR:Administrator Grants the very basic things needed to use Neos at all
TYPO3.Neos:LivePublisher   A “helper role” to allow publishing to the live workspace
TYPO3.Neos:RestrictedEditor TYPO3.Neos:AbstractEditor Allows to edit content but not publish to the live workspace
TYPO3.Neos:Editor

TYPO3.Neos:AbstractEditor

TYPO3.Neos:LivePublisher

Allows to edit and publish content
TYPO3.Neos:Administrator TYPO3.Neos:Editor Everything the Editor can do, plus admin things

To adjust permissions for your editors, you can of course just adjust the existing roles (TYPO3.Neos:RestrictedEditor and TYPO3.Neos:Editor in most cases). If you need different sets of permissions, you will need to define your own custom roles, though.

Those custom roles should inherit from RestrictedEditor or Editor and then grant access to the additional privilege targets you define (see below).

Here is an example for a role (limiting editing to a specific language) that shows this:

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\EditNodePrivilege':
    # this privilegeTarget is defined to switch to a "whitelist" approach
    'Acme.Com:EditAllNodes':
      matcher: 'TRUE'

    'Acme.Com:EditFinnish':
      matcher: 'isInDimensionPreset("language", "fi")'

roles:
  'TYPO3.Neos:Editor':
    privileges:
      -
        privilegeTarget: 'Acme.Com:EditAllNodes'
        permission: GRANT

  'Acme.Com:FinnishEditor':
    parentRoles: ['TYPO3.Neos:RestrictedEditor']
    privileges:
      -
        privilegeTarget: 'Acme.Com:EditFinnish'
        permission: GRANT

Node Privileges

Node privileges define what can be restricted in relation to accessing and editing nodes. In combination with matchers (see the next section) they allow to define privilege targets that can be granted or denied for specific roles.

Note

This is a blacklist by default, so the privilege won’t match if one of the conditions don’t match. So the example:

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\CreateNodePrivilege':
    'Some.Package:SomeIdentifier':
      matcher: >-
        isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")
        && createdNodeIsOfType("TYPO3.Neos.NodeTypes:Text")

will actually only affect nodes of that type (and subtypes). All users will still be able to create other node types, unless you also add a more generic privilege target:

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\CreateNodePrivilege':
    'Some.Package:SomeIdentifier':
      matcher: isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")

That will be abstained by default. It’s the same with MethodPrivileges, but with those we abstain all actions by default (in Neos that is).

NodeTreePrivilege

A privilege that prevents matching document nodes to appear in the Navigate Component. It also prevents editing of those nodes in case the editor navigates to a node without using the Navigate Component (e.g. by entering the URL directly).

Usage example:

privilegeTargets:
  'TYPO3\Neos\Security\Authorization\Privilege\NodeTreePrivilege':
    'Some.Package:SomeIdentifier':
      matcher: 'isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")'

This defines a privilege that intercepts access to the specified node (and all of its child nodes) in the node tree.

EditNodePropertyPrivilege

A privilege that targets editing of node properties.

Usage example:

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\EditNodePropertyPrivilege':
    'Some.Package:SomeIdentifier':
      matcher: >-
        isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")
        && nodePropertyIsIn(["hidden", "name"])

This defines a privilege target that intercepts editing the “hidden” and “name” properties of the specified node (and all of its child nodes).

ReadNodePropertyPrivilege

A privilege that targets reading of node properties.

Usage example:

'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\ReadNodePropertyPrivilege':
  'Some.Package:SomeIdentifier':
    matcher: 'isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")'

This defines a privilege target that intercepts reading any property of the specified node (and all of its child-nodes).

RemoveNodePrivilege

A privilege that targets deletion of nodes.

Usage example:

privilegeTargets:
 'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\RemoveNodePrivilege':
   'Some.Package:SomeIdentifier':
     matcher: 'isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")'

This defines a privilege target that intercepts deletion of the specified node (and all of its child-nodes).

CreateNodePrivilege

A privilege that targets creation of nodes.

Usage example:

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\CreateNodePrivilege':
    'Some.Package:SomeIdentifier':
      matcher: >-
        isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")
        && createdNodeIsOfType("TYPO3.Neos.NodeTypes:Text")

This defines a privilege target that intercepts creation of Text nodes in the specified node (and all of its child nodes).

EditNodePrivilege

A privilege that targets editing of nodes.

Usage example:

privilegeTargets:
 'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\EditNodePrivilege':
    'Some.Package:SomeIdentifier':
      matcher: >-
        isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")
        && nodeIsOfType("TYPO3.Neos.NodeTypes:Text")

This defines a privilege target that intercepts editing of Text nodes on the specified node (and all of its child nodes).

ReadNodePrivilege

The ReadNodePrivilege is used to limit access to certain parts of the node tree:

With this configuration, the node with the identifier c1e528e2-b495-0622-e71c-f826614ef287 and all its child nodes will be hidden from the system unless explicitly granted to the current user (by assigning SomeRole):

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\ReadNodePrivilege':
    'Some.Package:MembersArea':
      matcher: 'isDescendantNodeOf("c1e528e2-b495-0622-e71c-f826614ef287")'

roles:
  'Some.Package:SomeRole':
    privileges:
      -
        privilegeTarget: 'Some.Package:MembersArea'
        permission: GRANT

Privilege Matchers

The privileges need to be applied to certain nodes to be useful. For this, matchers are used in the policy, written using Eel. Depending on the privilege, various methods to address nodes are available.

Position in the Node Tree

This allows to match on the position in the node tree. A node matches if it is below the given node or the node itself.

Signature:
isDescendantNodeOf(node-path-or-identifier)
Parameters:
  • node-path-or-identifier (string) The nodes’ path or identifier
Applicable to:
matchers of all node privileges

Note

The node path is not reliable because it changes if a node is moved. And the path is not “human-readable” in Neos because new nodes get a unique random name. Therefore it is best practice not to rely on the path but on the identifier of a node.

NodeType

Matching against the type of a node comes in two flavors. Combining both allows to limit node creation in a sophisticated way.

The first one allows to match on the type a node has:

Signature:
nodeIsOfType(nodetype-name)
Parameters:
  • node-path-or-identifier (string|array) an array of supported node type identifiers or a single node type identifier
Applicable to:
matchers of all node privileges

Inheritance is taken into account, so that specific types also match if a supertype is given to this matcher.

The second one allows to match on the type of a node that is being created:

Signature:
createdNodeIsOfType(nodetype-identifier)
Parameters:
  • nodetype-identifier (string|array) an array of supported node type identifiers or a single node type identifier
Applicable to:
matchers of the CreateNodePrivilege

This acts on the type of the node that is about to be created.

Workspace Name

This allows to match against the name of a workspace a node is in.

Signature:
isInWorkspace(workspace-names)
Parameters:
  • workspace-names (string|array) an array of workspace names or a single workspace name
Applicable to:
matchers of all node privileges
Property Name

This allows to match against the name of a property that is going to be affected.

Signature:
nodePropertyIsIn(property-names)
Parameters:
  • property-names (string|array) an array of property names or a single property name
Applicable to:
matchers of he ReadNodePropertyPrivilege and the EditNodePropertyPrivilege
Content Dimension

This allows to restrict editing based on the content dimension a node is in. Matches if the currently-selected preset in the passed dimension name is one of presets.

Signature:
isInDimensionPreset(name, value)
Parameters:
  • name (string) The content dimension name
  • presets (string|array) The preset of the content dimension
Applicable to:
matchers of all node privileges

The following example first blocks editing of nodes completely (by defining a privilege target that always matches) and then defines a privilege target matching all nodes having a value of “de” for the “language” content dimension. That target is then granted for the “Editor” role.

privilegeTargets:
  'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\EditNodePrivilege':
    # This privilegeTarget must be defined, so that we switch to a "whitelist" approach
    'Neos.Demo:EditAllNodes':
      matcher: 'TRUE'

    'Neos.Demo:EditGerman':
      matcher: 'isInDimensionPreset("language", "de")'

roles:
  'TYPO3.Neos:Editor':
    privileges:
      -
        privilegeTarget: 'Neos.Demo:EditGerman'
        permission: GRANT

Restricting Access to Backend Modules

Restrict Module Access

The available modules are defined in the settings of Neos. Along with those settings privilege targets can be defined. Those are used to remove the module from the UI if access would not be granted. Here is a shortened example containing only the relevant parts:

TYPO3:
 Neos:
   modules:
    management:
      privilegeTarget: 'TYPO3.Neos:Backend.Module.Management'
      submodules:
        workspaces:
          privilegeTarget: 'TYPO3.Neos:Backend.Module.Management.Workspaces'

The targets are defined as usual in the security policy, here is a shortened example:

'TYPO3.Neos:Backend.Module.Management':
  matcher: 'method(TYPO3\Neos\Controller\Module\ManagementController->indexAction())'

'TYPO3.Neos:Backend.Module.Management.Workspaces':
  matcher: >-
    method(
      TYPO3\Neos\Controller\Module\Management\WorkspacesController
      ->(publishNode|discardNode|publishOrDiscardNodes)Action()
    ) || method(TYPO3\Neos\Service\Controller\AbstractServiceController->(error)Action())

Now those privilege targets can be used to grant/deny access for specific roles.

Disable Modules

To completely disable modules available in the Neos UI a setting can be used:

TYPO3:
  Neos:
    modules:
      management:
        submodules:
          history:
            enabled: FALSE

Limitations

Except for the assignment of roles to users there is no UI for editing security related configuration. Any needed changes have to be made to the policies in Policy.yaml.

Further Reading

The privileges specific to Neos are built based on top of the Flow security features. Read the corresponding documentation.

Extending Neos

Creating a plugin

Any Flow package can be used as a plugin with a little effort. This section will guide you through a simple example. First, we will create a really basic Flow package. Second, we’ll expose this Flow package as a Neos plugin.

Creating a Flow package

First we will create a very simple Flow package to use for integrating it as a plugin.

Note

When developing sites the need for simple plugins will often arise. And those small plugins will be very site-specific most of the time. In these cases it makes sense to create the needed code inside the site package, instead of in a separate package.

For the sake of simplicity we will create a separate package now.

If you do not have the Kickstart package installed, you must do this now:

cd /your/htdocs/Neos
php /path/to/composer.phar require typo3/kickstart \*

Now create a package with a model, so we have something to show in the plugin:

./flow kickstart:package Sarkosh.CdCollection
./flow kickstart:model Sarkosh.CdCollection Album title:string year:integer description:string rating:integer
./flow kickstart:repository Sarkosh.CdCollection Album

Then generate a migration to create the needed DB schema:

./flow doctrine:migrationgenerate

The command will ask in which directory the migration should be stored. Select the package Sarkosh.CdCollection. Afterwards the migration can be applied:

./flow doctrine:migrate

You should now have a package with a default controller and templates created.

Configure Access Rights

To be able to call the actions of the controller you have to configure a matching set of rights. Add the following to Configuration/Policy.yaml of your package:

privilegeTargets:
  TYPO3\Flow\Security\Authorization\Privilege\Method\MethodPrivilege:
    'Sarkosh.CdCollection:StandardControllerActions':
      matcher: 'method(Sarkosh\CdCollection\Controller\StandardController->(index)Action())'

roles:
  'TYPO3.Flow:Everybody':
    privileges:
      -
        privilegeTarget: 'Sarkosh.CdCollection:StandardControllerActions'
        permission: GRANT

Note

If you add new actions later on you will have to extend the matcher rule to look like (index|other|third).

Configure Routes

To actually call the plugin via HTTP request you have to include the Flow default-routes into the Configuration/Routes.yaml of your whole setup (before the Neos routes):

##
# Flow subroutes
-
  name: 'Flow'
  uriPattern: 'flow/<FlowSubroutes>'
  defaults:
    '@format': 'html'
  subRoutes:
    FlowSubroutes:
      package: TYPO3.Flow

The frontend of your plugin can now be called via http://neos.demo/flow/sarkosh.cdcollection. We specifically use the flow prefix here to ensure that the routes of Flow do not interfere with Neos.

Note

The routing configuration will become obsolete as soon as you use the package as as Neos-Plugin as described in the following steps.

Add data

Now you can add some entries for your CD collection in the database:

INSERT INTO sarkosh_cdcollection_domain_model_album (
  persistence_object_identifier, title, year, description, rating
) VALUES (
  uuid(), 'Jesus Christ Superstar', '1970',
  'Jesus Christ Superstar is a rock opera by Andrew Lloyd Webber, with lyrics by Tim Rice.',
  '5'
);

(or using your database tool of choice) and adjust the templates so a list of CDs is shown. When you are done with that, you can make a plugin out of that.

As an optional step you can move the generated package from its default location Packages/Application/ to Packages/Plugins. This is purely a convention and at times it might be hard to tell an “application package” from a “plugin”, but it helps to keep things organized. Technically it has no relevance.

mkdir Packages/Plugins
mv Packages/Application/Sarkosh.CdCollection Packages/Plugins/Sarkosh.CdCollection

Converting a Flow Package Into a Neos Plugin

To activate a Flow package as a Neos plugin, you only need to provide two configuration blocks.

Add a NodeType

First, you need to add a new node type for the plugin, such that the user can choose the plugin from the list of content elements:

Add the following to Configuration/NodeTypes.yaml of your package:

'Sarkosh.CdCollection:Plugin':
  superTypes:
    'TYPO3.Neos:Plugin': TRUE
  ui:
    label: 'CD Collection'
    group: 'plugins'

This will add a new entry labeled “CD Collection” to the “Plugins” group in the content element selector (existing groups are General, Structure and Plugins).

Configure TypoScript

Second, the rendering of the plugin needs to be specified using TypoScript, so the following TypoScript needs to be added to your package.

Resources/Private/TypoScript/Plugin.ts2:

prototype(Sarkosh.CdCollection:Plugin) < prototype(TYPO3.Neos:Plugin)
prototype(Sarkosh.CdCollection:Plugin) {
      package = 'Sarkosh.CdCollection'
      controller = 'Standard'
      action = 'index'
}

Finally tweak your site package’s Root.ts2 and include the newly created TypoScript file:

include: Plugin.ts2

Now log in to your Neos backend (you must remove the Flow routes again), and you will be able to add your plugin just like any other content element.

To automatically include the Root.ts2 in Neos you have to add the following lines to the Configuration/Settings.yaml of your Package:

TYPO3:
  Neos:
    typoScript:
      autoInclude:
        'Sarkosh.CdCollection': TRUE
Use TypoScript to configure the Plugin

To hand over configuration to your plugin you can add arbitrary TypoScript values to Resources/Private/TypoScript/Plugin.ts2:

prototype(Sarkosh.CdCollection:Plugin) {
      ...
      myNodeName = ${q(node).property('name')}
}

In the controller of your plugin you can access the value from TypoScript like this.

$myNodeName = $this->request->getInternalArgument('__myNodeName');

Linking to a Plugin

Inside of your Plugin you can use the usual f:link.action and f:uri.action ViewHelpers from fluid to link to other ControllerActions:

<f:link.action package="sarkosh.cdcollection" controller="standard" action="show" arguments="{collection: collection}" />

If you want to create links to your plugin from outside the plugin context you have to use one of the following methods.

To create a link to a ControllerAction of your Plugin in TypoScript you can use the following code:

link = TYPO3.Neos:NodeUri {
      # you have to identify the document that contains your plugin somehow
      node = ${q(site).find('[instanceof Sarkosh.CdCollection:Plugin]').first().closest('[instanceof TYPO3.Neos:Document]').get(0)}
      absolute = true
      additionalParams = ${{'--sarkosh_cdcollection-plugin': {'@package': 'sarkosh.cdcollection', '@controller':'standard', '@action': 'show', 'collection': collection}}}
}

The same code in a fluid template looks like this:

{namespace neos=TYPO3\Neos\ViewHelpers}
<neos:uri.node node="{targetNode}" arguments="{'--sarkosh_cdcollection-plugin': {'@package': 'sarkosh.cdcollection', '@controller':'standard', '@action': 'show', 'collection': collection}}" />

Configuring a plugin to show specific actions on different pages

With the simple plugin you created above, all of the actions of that plugin are executed on one specific page node. But sometimes you might want to break that up onto different pages. For this use case there is a node type called Plugin View. A plugin view is basically a view of a specific set of actions configured in your NodeTypes.yaml.

The steps to have one plugin which is rendered at multiple pages of your website is as follows:

  1. Create your plugin as usual; e.g. like in the above example.
  2. Insert your plugin at a specific page, just as you would do normally. This is later called the Master View of your plugin.
  3. You need to define the parts of your plugin you lateron want to have separated in a different page. This is done in the options.pluginViews setting inside NodeTypes.yaml (see below).
  4. Then, in Neos, insert a Plugin View instance on the other page where you want a part of the plugin to be rendered. In the inspector, you can then select the Plugin instance inside the Master View option, and afterwards choose the specific Plugin View you want to use.

You can update your Configuration/NodeTypes.yaml like this to configure which actions will be available for the Plugin View:

'Sarkosh.CdCollection:Plugin':
  superTypes:
    'TYPO3.Neos:Plugin': TRUE
  ui:
    label: 'CD Collection'
    group: 'plugins'
  options:
    pluginViews:
      'CollectionShow':
        label: 'Show Collection'
        controllerActions:
          'Sarkosh\CdCollection\Controller\CollectionController': ['show']
      'CollectionOverview':
        label: 'Collection Overview'
        controllerActions:
          'Sarkosh\CdCollection\Controller\CollectionController': ['overview']

When you insert a plugin view for a node the links in both of the nodes get rewritten automatically to link to the view or plugin, depending on the action the link points to. Insert a “Plugin View” node in your page, and then, in the inspector, configure the “Master View” (the master plugin instance) and the “Plugin View”.

Fixing Plugin Output

If you reuse an existing flow-package a plugin in Neos and check the HTML of a page that includes your plugin, you will clearly see that things are not as they should be. The plugin is included using its complete HTML, including head and body tags. This of course results in an invalid document.

To improve that you can add a Configration/Views.yaml file to your Package that can be used to alter the used template and views based on certain conditions. The documentation for that can be found in the Flow Framework Documentation.

Optimizing the URLs

By default Neos will create pretty verbose urls for your plugin. To avoid that you have to configure a proper routing for your Package.

Plugin Request and Response

The plugin controller action is called as a child request within the parent request. Alike that, the response is also a child response of the parent and will be handed up to the parent.

Warning

The documentation is not covering all aspects yet. Please have a Look at the How To’s Section as well.

Custom Backend Modules

If you want to integrate custom backend functionality you can do so by adding a submodule to the administration or management section of the main menu. Alternatively a new top level section can be created either by adding a overview module like the the existing ones or a normal module.

Some possible use cases would be the integrating of external web services, triggering of import or export actions or creating of editing interfaces for domain models from other packages.

Warning

This is not public API yet due to it’s unpolished state and is subject to change in the future.

Controller Class

Implementing a Backend Module starts by creating an action controller class derived from \TYPO3\Flow\Mvc\Controller\ActionController

Classes/Vendor/Site/Domain/Controller/BackendController:

namespace Vendor\Site\Controller;

use TYPO3\Flow\Annotations as Flow;

class BackendController extends \TYPO3\Flow\Mvc\Controller\ActionController {
        public function indexAction() {
                $this->view->assign('exampleValue', 'Hello World');
        }
}

Fluid Template

The user interface of the module is defined in a fluid template in the same way the frontend of a website is defined.

Resources/Private/Templates/Backend/Index.html:

{namespace neos=TYPO3\Neos\ViewHelpers}
<div class="neos-content neos-container-fluid">
        <h1></h1>
        <p>{exampleValue}</p>
</div>

Note

Neos comes with some ViewHelpers for easing backend tasks. Have a look at the neos:backend ViewHelpers from the Neos ViewHelper Reference

Access Rights

To use the module the editors have to be granted access to the controller actions of the module.

Configuration/Policy.yaml:

privilegeTargets:

  'TYPO3\Flow\Security\Authorization\Privilege\Method\MethodPrivilege':
        'Vendor.Site:BackendModule':
          matcher: 'method(Vendor\Site\Controller\BackendController->.*Action())'

roles:

  'TYPO3.Neos:Editor':
        privileges:
          -
                privilegeTarget: 'Vendor.Site:BackendModule'
                permission: GRANT

Configuration

To show up in the management or the administration section the module is defined in the package settings.

Configuration/Settings.yaml:

TYPO3:
  Neos:
        modules:
          management:
                submodules:
                  exampleModule:
                        label: 'Example Module'
                        controller: 'Vendor\Site\Controller\BackendController'
                        description: 'An Example for implementing Backend Modules'
                        icon: 'icon-star'
                        privilegeTarget: 'Vendor.Site:BackendModule'

Tip

Neos contains several backend modules built with the same API which can be used for inspiration.

Custom Edit/Preview-Modes

From the beginning the Neos backend was designed to be extensible with different rendering modes users can switch depending on their use-case. In-place editing and the raw-content-editing-mode are only a small glimpse of what is possible.

It is encouraged to add custom edit- or preview modes. Use-cases could be the preview of the content in search engines or on mobile devices.

Add a custom Preview Mode

Edit/preview modes are added to the Neos-Backend via Settings.yaml.

TYPO3:
  Neos:
    userInterface:
      editPreviewModes:
        print:
          title: 'Print'
          # show as edit mode
          isEditingMode: FALSE
          # show as preview mode
          isPreviewMode: TRUE
          # render path
          typoScriptRenderingPath: 'print'
          # show after the existing modes
          position: 200

The settings isEditingMode and isPreviewMode are controlling whether the mode will show up in the section “Edit” or “Preview” of the Neos-Backend. The major difference between both sections is that inside “Preview” section the inline editing options are not activated.

The actual rendering of the edit/preview mode is configured in TypoScript:

print < page
print {
        head {
                stylesheets.printCss = TYPO3.TypoScript:Tag {
                        @position = 'end 10'
                        tagName = 'link'
                        attributes {
                                media = 'all'
                                rel = 'stylesheet'
                                href = TYPO3.TypoScript:ResourceUri {
                                        path = 'resource://Neos.Demo/Public/Styles/Print.css'
                                }
                        }
                }
        }
}

In this example the default rendering as defined in the path page is used and altered to include the Print.css for all media.

Add a custom Editing Mode

To add an editing mode instead of a preview mode the configuration in Settings.yaml has to be changed.

TYPO3:
  Neos:
    userInterface:
      editPreviewModes:
        print:
          isEditingMode: TRUE
          isPreviewMode: FALSE

Warning

It is currently possible to configure an edit/preview-mode for editing and preview at the same time. We are still unsure whether this is a bug or a feature – so this behavior may change in future releases.

Custom Editors

Like with validators, using custom editors is possible as well. Every dataType has its default editor set, which can have options applied like:

TYPO3:
  Neos:
    userInterface:
      inspector:
        dataTypes:
          'string':
            editor: 'TYPO3.Neos/Inspector/Editors/TextFieldEditor'
            editorOptions:
              placeholder: 'This is a placeholder'

On a property level this can be overridden like:

TYPO3:
  Neos:
    userInterface:
      inspector:
        properties:
          'string':
            editor: 'My.Package/Inspector/Editors/TextFieldEditor'
            editorOptions:
              placeholder: 'This is my custom placeholder'

Namespaces can be registered like this, as with validators:

TYPO3:
  Neos:
    userInterface:
      requireJsPathMapping:
        'My.Package/Editors': 'resource://My.Package/Public/Scripts/Inspector/Editors'

Editors should be named <SomeType>Editor and can be referenced by My.Package/Inspector/Editors/MyCustomEditor for example.

Registering specific editors is also possible like this:

TYPO3:
  Neos:
    userInterface:
      inspector:
        editors:
          'TYPO3.Neos/BooleanEditor':
            path: 'resource://TYPO3.Neos/Public/JavaScript/Content/Inspector/Editors/BooleanEditor'

Custom Eel Helper

Eel Helpers provide methods that can be used inside of Eel expressions. That is mostly used to extend the capabilities for data-aquisition and processing of TypoScript.

The first step is to create the EelHelper class. Every Helper has to implement the interface TYPO3\Eel\ProtectedContextAwareInterface.

namespace Vendor\Site\Eel\Helper;

use TYPO3\Flow\Annotations as Flow;
use TYPO3\Eel\ProtectedContextAwareInterface;

class ExampleHelper implements ProtectedContextAwareInterface {

        /**
         * Wrap the incoming string in curly brackets
         *
         * @param $text string
         * @return string
         */
        public function wrapInCurlyBrackets($text) {
                return '{' . $text . '}';
        }

        /**
         * All methods are considered safe, i.e. can be executed from within Eel
         *
         * @param string $methodName
         * @return boolean
         */
        public function allowsCallOfMethod($methodName) {
                return TRUE;
        }

}

Afterwards the namespace of the Helper has to be registered for usage in TypoScript in the Settings.yaml of the package:

TYPO3:
  TypoScript:
    defaultContext:
      'Vendor.Example': 'Vendor\Site\Eel\Helper\ExampleHelper'

In TypoScript you can call the methods of the helper inside of EelExpressions:

exampleEelValue = ${Vendor.Example.wrapInCurlyBrackets('Hello World')}

Custom FlowQuery Operations

The FlowQuery EelHelper provides you with methods to traverse the ContentRepository. Implementing custom operations allows the creation of filters, sorting algorithms and much more.

Warning

This has not been declared a public api yet and still might change a bit in future release. Nevertheless it is an important functionality and this or a similar mechanism will still be available in the future.

Create FlowQuery Operation

Implementing a custom operation is done by extending the TYPO3\Eel\FlowQuery\Operations\AbstractOperation class. The Operation is implemented in the evaluate method of that class.

To identify the operation lateron in TypoScript the static class variable $shortName has to be set.

If you pass arguments to the FlowQuery Operation they end up in the numerical array $arguments that is handed over to the evaluate method.

namespace Vendor\Site\FlowQuery\Operation;

use TYPO3\Eel\FlowQuery\FlowQuery;
use TYPO3\Eel\FlowQuery\Operations\AbstractOperation;

class RandomElementOperation extends AbstractOperation {

        /**
         * {@inheritdoc}
         *
         * @var string
         */
        static protected $shortName = 'randomElement';

        /**
         * {@inheritdoc}
         *
         * @param FlowQuery $flowQuery the FlowQuery object
         * @param array $arguments the arguments for this operation
         * @return void
         */
        public function evaluate(FlowQuery $flowQuery, array $arguments) {
                $context = $flowQuery->getContext();
                $randomKey = array_rand($context);
                $result = array($context[$randomKey]);
                $flowQuery->setContext($result);
        }
}

In TypoScript you can use this operation to find a random element of the main ContentCollection of the Site-Node:

randomStartpageContent = ${q(site).children('main').children().randomElement()}

Note

For overriding existing operations another operation with the same shortName but a higher priority can be implemented.

Create Final FlowQuery Operations

If a FlowQuery operation does return a value instead of modifying the FlowQuery Context it has to be declared $final.

namespace Vendor\Site\FlowQuery\Operation;

use TYPO3\Eel\FlowQuery\FlowQuery;
use TYPO3\Eel\FlowQuery\Operations\AbstractOperation;

class DebugOperation extends AbstractOperation {

        /**
         * If TRUE, the operation is final, i.e. directly executed.
         *
         * @var boolean
         * @api
         */
        static protected $final = TRUE;

        /**
         * {@inheritdoc}
         *
         * @param FlowQuery $flowQuery the FlowQuery object
         * @param array $arguments the arguments for this operation
         * @return void
         */
        public function evaluate(FlowQuery $flowQuery, array $arguments) {
                return \TYPO3\Flow\var_dump($flowQuery->getContext(), NULL, TRUE);
        }
}

Further Reading

  1. For checking that the operation can actually work on the current context a canEvaluate method can be implemented.
  2. You sometimes might want to use the Fizzle Filter Engine to use jQuery like selectors in the arguments of your
    operation. Therefore you can apply a filter operation that is applied to the context as follows: $flowQuery->pushOperation('filter', $arguments);.

Custom TypoScript Objects

By adding custom TypoScript Objects it is possible to extend the capabilities of TypoScript in a powerful and configurable way. If you need to write a way to execute PHP code during rendering, for simple methods, Eel helpers should be used. For more complex functionality where custom classes with more configuration options are needed, TypoScript objects should rather be created.

As an example, you might want to create your own TypoScript objects if you are enriching the data that gets passed to the template with external information from an API or if you have to convert some entities from identifier to domain objects.

In the example below, a Gravatar image tag is generated.

Create a TypoScript Object Class

To create a custom TypoScript object the TYPO3\TypoScript\TypoScriptObjects\AbstractTypoScriptObject class is extended. The only method that needs to be implemented is evaluate(). To access values from TypoScript the method $this->tsValue('__ts_value_key__'); is used:

namespace Vendor\Site\TypoScript;

use TYPO3\Flow\Annotations as Flow;
use TYPO3\TypoScript\TypoScriptObjects\AbstractTypoScriptObject;

class GravatarImplementation extends AbstractTypoScriptObject {
        public function evaluate() {
                $emailAddress = $this->tsValue('emailAddress');
                $size = $this->tsValue('size') ? $this->tsValue('size') : 80;
                $gravatarImageSource = 'http://www.gravatar.com/avatar/' . md5( strtolower( trim( $emailAddress ) ) ) . "?s=$size&d=mm&r=g";
                return '<img src="' . $gravatarImageSource . '" alt="" />';
        }
}

To use this implementation in TypoScript, you have to define a TS2-prototype first:

prototype(Vendor.Site:Gravatar) {
        @class = 'Vendor\\Site\\TypoScript\\GravatarImplementation'
        emailAddress = ''
        size = 80
}

Afterwards the prototype can be used in TypoScript:

garavatarImage = Vendor.Site:Gravatar
garavatarImage {
        emailAddress = 'kasper@typo3.org'
        size = 120
}

Custom Validators

It is possible to register paths into RequireJS (the JavaScript file and module loader used by Neos, see http://requirejs.org) and by this custom validators into Neos. Validators should be named ‘<SomeType>Validator’, and can be referenced by My.Package/Public/Scripts/Validators/FooValidator for example.

Namespaces can be registered like this in Settings.yaml:

TYPO3:
  Neos:
    userInterface:
      requireJsPathMapping:
        'My.Package/Validation': 'resource://My.Package/Public/Scripts/Validators'

Registering specific validators is also possible like this:

TYPO3:
  Neos:
    userInterface:
      validators:
        'My.Package/AlphanumericValidator':
          path: 'resource://My.Package/Public/Scripts/Validators/FooValidator'

Custom ViewHelpers

Custom ViewHelpers are the way to extend the Fluid templating engine to the needs of your project.

Note

The full documentation for writing ViewHelpers is included in the Flow documentation This documentation is a short introduction of the basic principles.

Create A ViewHelper Class

If you want to create a ViewHelper that you can call from your template (as a tag), you write a php class which has to inherit from \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper (or its subclasses). You need to implement only one method to write a view helper:

namespace Vendor\Site\ViewHelpers;
class TitleViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper {
        public function render() {
                return 'Hello World';
        }
}

Afterwards you have to register the namespace of your ViewHelper in the template before actually using it:

{namespace site=Vendor\Site\ViewHelpers}
<!-- tag syntax -->
<site:title />

<!-- inline syntax -->
{site:title()}

Note

Please look at the Templating documentation for an in-depth explanation of Fluid templating.

Declare View Helper Arguments

There exist two ways to pass arguments to a ViewHelper that can be combined:

  1. Add arguments to the render-method of the ViewHelper Class:

    namespace Vendor\Site\ViewHelpers;
    
    class TitleViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper {
            /**
             * Render the title and apply some magic
             *
             * @param string $title the title
             * @param string $value If $key is not specified or could not be resolved, this value is used. If this argument is not set, child nodes will be used to render the default
             * @return string Translated label or source label / ID key
             * @throws \TYPO3\Fluid\Core\ViewHelper\Exception
             */
            public function render($title, $flag = FALSE) {
    
                    # apply magic here ...
    
                    return '<h1>' . $title . '</h1>';
            }
    }
    
  2. Use the registerArgument method of the AbstractViewHelper Class:

    This is especially useful if you have to define lots of arguments or create base classes for derived ViewHelpers.

    namespace Vendor\Site\ViewHelpers;
    
    class TitleViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper {
    
            /**
             * Initialize arguments
             *
             * @return void
             */
            public function initializeArguments() {
                    $this->registerArgument('title', 'string', 'The Title to render');
                    $this->registerArgument('flag', 'boolean', 'A ');
            }
    
            public function render() {
                    $title = $this->arguments['title'];
                    $flag = $this->arguments['flag'];
    
                    # apply magic here ...
    
                    return '<h1>' . $title . '</h1>';
            }
    }
    

Context and Children

If your ViewHelper contains HTML code and possibly other ViewHelpers as well, the content of the ViewHelper can be rendered and used for further processing:

public function render($title = NULL) {
        if ($title === NULL) {
                $title = $this->renderChildren();
        }
        return '<h1>' . $title . '</h1>';
}

Note

It is a good practice to support passing of the main context as argument or children for flexibility an ease of use.

Sometimes your ViewHelper has to interact with other ViewHelpers insider that are rendered via $this->renderChildren(). To do that you can modify the context for the fluid rendering of the children. That allows keeping the scope of every ViewHelper clean and the implementation simple.

public function render() {
        # get the template variable container
        $templateVariableContainer = $renderingContext->getTemplateVariableContainer();
        # add a variable to the context
        $templateVariableContainer->add('salutation', 'Hello World');
        # render the children, the variable salutation is available for the child view helpers
        $result = $this->renderChildren();
        # remove the added variable again from the context
        $templateVariableContainer->remove('salutation');
        return $result;
}

Note

It is a considered a good practice to create a bunch of simple ViewHelpers that interact via Fluid context instead of creating complex logic inside a single ViewHelper.

Further reading

  1. TagBased ViewHelpers - For the common case that a ViewHelper renders a single HTML-Tag as a result there is a special base class. The TagBased ViewHelper contains automatic security measures, so if you use this, the likelyhood of cross-site-scripting vulnerabilities is greatly reduced.

    To find out more about that please lookup AbstractTagBasedViewHelper in the Flow documentation

  2. Condition ViewHelpers - To provide ViewHelpers that are doing either this or that there is a base class AbstractConditionViewHelper. This can be used in cases where you cannot express your condition via <f:if condition="..." >. To find out more about that please lookup AbstractTagBasedViewHelper in the Flow-Documentation.

  3. Widget ViewHelpers - If a view helper needs complex controller logic, has to interact with repositories to fetch data, needs some ajax-interaction or needs a Fluid-Template for rendering, you can create a Fluid Widget. It is possible to override the Fluid Template of a Widget in another package so this also provides a way to create extensible ViewHelpers.

Customizing the Inspector

When you add a new node type, you can customize the rendering of the inspector. Based on the first node that we created in the “CreatingContentElement” cookbook, we can add some properties in the inspector.

Add a simple checkbox element

This first example adds a checkbox, in a dedicated inspector section, to define if we need to hide the Subheadline property.

You can just add the following configuration to your NodesType.yaml, based on the previous cookbook example:

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml)

'Vendor.Site:YourContentElementName':
  ui:
    inspector:
      groups:
        advanced:
          label: 'Advanced'
          icon: 'icon-fort-awesome'
          position: 2
  properties:
    hideSubheadline:
      type: boolean
      defaultValue: TRUE
      ui:
        label: 'Hide Subheadline ?'
        reloadIfChanged: TRUE
        inspector:
          group: 'advanced'

You can add this property to your TypoScript:

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScripts/Library/Root.ts2)

prototype(Vendor.Site:YourContentElementName) < prototype(TYPO3.Neos:Content) {
  templatePath = 'resource://Vendor.Site/Private/Templates/TypoScriptObjects/YourContentElementName.html'
  headline = ${q(node).property('headline')}
  subheadline = ${q(node).property('subheadline')}
  hideSubheadline = ${q(node).property('hideSubheadline')}
  text = ${q(node).property('text')}
  image = ${q(node).property('image')}
}

And you can use it in your Fluid template:

HTML (Vendor.Site/Private/Templates/TypoScriptObjects/YourContentElementName.html)

{namespace neos=TYPO3\Neos\ViewHelpers}
<neos:contentElement node="{node}">
  <article>
    <header>
      <h2><neos:contentElement.editable property="headline">{headline -> f:format.raw()}</neos:contentElement></h2>
      <f:if condition="{hideSubheadline}">
        <f:else>
          <h3><neos:contentElement.editable property="subheadline">{subheadline -> f:format.raw()}</neos:contentElement></h3>
        </f:else>
      </f:if>
    </header>
    ...
  </article>
</neos:contentElement>

Add a simple selectbox element

The second example is about adding a selector to change the class of the article element:

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml)

'Vendor.Site:YourContentElementName':
  ui:
    inspector:
      groups:
        advanced:
          label: 'Advanced'
          position: 2
          icon: 'icon-fort-awesome'
  properties:
    articleType:
      type: string
      defaultValue: ''
      ui:
        label: 'Article Type'
        reloadIfChanged: TRUE
        inspector:
          group: 'advanced'
          editor: Content/Inspector/Editors/SelectBoxEditor
          editorOptions:
            placeholder: 'What kind of article ...'
            values:
              '':
                label: ''
              announcement:
                label: 'Announcement'
              casestudy:
                label: 'Case Study'
              event:
                label: 'Event'

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScripts/Library/Root.ts2)

prototype(Vendor.Site:YourContentElementName) < prototype(TYPO3.TypoScript:Template) {
  templatePath = 'resource://Vendor.Site/Private/Templates/TypoScriptObjects/YourContentElementName.html'
  headline = ${q(node).property('headline')}
  subheadline = ${q(node).property('subheadline')}
  articleType = ${q(node).property('articleType')}
  text = ${q(node).property('text')}
  image = ${q(node).property('image')}
}

HTML (Vendor.Site/Private/Templates/TypoScriptObjects/YourContentElementName.html)

{namespace neos=TYPO3\Neos\ViewHelpers}
<neos:contentElement node="{node}">
  <article{f:if(condition:articleType,then:' class="{articleType}"')}>
    ...
  </article>
</neos:contentElement>

Select multiple options in a selectbox element

For selecting more than one item with a slect box the type of the property has to be set to array.

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml):

'Vendor.Site:YourContentElementName':
  properties:
    tags:
      type: array
      ...
      ui:
        inspector:
          ...
          editor: Content/Inspector/Editors/SelectBoxEditor
          editorOptions:
            multiple: TRUE
            allowEmpty: FALSE
            values:
              ...

Use custom DataSources for a selectbox element

To add custom selectbox-options, Neos uses data sources for the inspector that can be implemented in PHP. See Data sources for more details.

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml):

'Vendor.Site:YourContentElementName':
  properties:
    articleType:
      ui:
        inspector:
          editor: Content/Inspector/Editors/SelectBoxEditor
          editorOptions:
            dataSourceIdentifier: 'acme-yourpackage-test'

Remove fields from an existing Node Type

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml):

'TYPO3.Neos:Plugin':
  properties:
    package:    [ ]
    subpackage: [ ]
    controller: [ ]
    action:     [ ]

Remove a selectbox option from an existing Node Type

Removing a selectbox option, can be done by simply edition your NodeTypes.yaml.

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml):

'TYPO3.Neos:Shortcut':
  properties:
    targetMode:
      ui:
        inspector:
          editorOptions:
            values:
              parentNode: ~

It is also possible to add Custom Editors and use Custom Validators.

Data sources

Data sources allow easy integration of data source end points, to provide data to the editing interface without having to define routes, policies, controller.

Data sources can be used for various purposes, however the return format is restricted to JSON. An example of their usage is as a data provider for the inspector SelectBoxEditor (see Property Type: string / array<string> SelectBoxEditor – Dropdown Select Editor for details).

A data source is defined by an identifier and this identifier has to be unique.

To implement a data source, create a class that implements TYPO3\Neos\Service\DataSource\DataSourceInterface, preferably by extending TYPO3\Neos\Service\DataSource\AbstractDataSource. Then set the static protected property identifier to a string. Make sure you use a unique identifier, e.g. acme-demo-available-dates.

Then implement the getData method, with the following signature:

/**
 * Get data
 *
 * The return value must be JSON serializable data structure.
 *
 * @param NodeInterface $node The node that is currently edited (optional)
 * @param array $arguments Additional arguments (key / value)
 * @return mixed JSON serializable data
 * @api
 */
public function getData(NodeInterface $node = null, array $arguments);

The return value of the method will be JSON encoded.

Data sources are available with the following URI pattern /neos/service/data-source/<identifier>, which can be linked to using the follow parameters:

  • @package: ‘TYPO3.Neos’
  • @subpackage: ‘Service’
  • @controller: ‘DataSource’
  • @action: ‘index
  • @format: ‘json’
  • dataSourceIdentifier: ‘<identifier>’

Arbitrary additional arguments are allowed. Additionally the routing only accepts GET requests.

If additional arguments are provided then they will automatically be available in the $arguments parameter of the getData method. Additional arguments will not be property mapped, meaning they will contain their plain value. However if an argument with the key node is provided, it will automatically be converted into a node. Provide a valid node path to use this, and keep in mind that the node argument is restricted to this use-case. This is done to make working with nodes easy.

The dataSourceIdentifier will automatically be removed from the arguments parameter.

Note

Data sources are restricted to only be accessible for users with the TYPO3.Neos:Backend.DataSource privilege, which is included in the TYPO3.Neos:Editor role. This means that a user has to have access to the backend to be able to access a data point.

Example TestDataSource.php:

<?php
namespace Acme\YourPackage\DataSource;

use TYPO3\Neos\Service\DataSource\AbstractDataSource;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;

class TestDataSource extends AbstractDataSource {

    /**
     * @var string
     */
    static protected $identifier = 'acme-yourpackage-test';

    /**
     * Get data
     *
     * @param NodeInterface $node The node that is currently edited (optional)
     * @param array $arguments Additional arguments (key / value)
     * @return array JSON serializable data
     */
    public function getData(NodeInterface $node = NULL, array $arguments)
    {
        return isset($arguments['integers']) ? array(1, 2, 3) : array('a', 'b', 'c');
    }
}

Interaction with the Neos backend

JavaScript events

Some sites will rely on JavaScript initialization when the page is rendered, typically on DocumentReady, and typically via jQuery or similar framework. The Neos backend will however often reload the page via Ajax whenever a node property is changed, and this might break functionality on sites relying on custom JavaScript being executed on DocumentReady.

To fix this, the Neos backend will dispatch an event when the page is reloaded via ajax, and site specific JavaScript can listen on this event to trigger whatever code is needed to render the content correctly.

if (typeof document.addEventListener === 'function') {
      document.addEventListener('Neos.PageLoaded', function(event) {
              // Do stuff
      }, false);
}

The event object given, will always have the message and time set on event.detail. Some events might have more attributes set.

Note that this only works in IE9+, Safari, Firefox and Chrome. For earlier IE versions the events are not triggered.

The Neos backend will dispatch events that can be listened on when the following events occur:

  • Neos.PageLoaded Whenever the page reloads by Ajax.
  • Neos.PreviewModeActivated When the backend switches from edit to preview mode.
  • Neos.PreviewModeDeactivated When the backend switches from preview to edit mode.
  • Neos.ContentModuleLoaded When the content module is loaded (i.e. when a user is logged in).
  • Neos.NodeCreated When a new node was added to the document. The event has a reference to the DOM element in event.detail.element. Additional information can be fetched through the element’s attributes.
  • Neos.NodeRemoved When a new node was removed from the document. The event has a reference to the DOM element in event.detail.element. Additional information can be fetched through the element’s attributes.
  • Neos.NodeSelected When a node existing on the page is selected. The event has a reference to the DOM element in event.detail.element and the node model object in event.detail.node. Additional information can be fetched through the node model.
  • Neos.LayoutChanged When the content window layout changes (when panels that alter the body margin are opened/closed).
  • Neos.NavigatePanelOpened When the navigate panel is opened.
  • Neos.NavigatePanelClosed When the inspector panel is closed.
  • Neos.InspectorPanelOpened When the navigate panel is opened.
  • Neos.InspectorPanelClosed When the inspector panel is closed.
  • Neos.EditPreviewPanelOpened When the edit/preview panel is opened.
  • Neos.EditPreviewPanelClosed When the edit/preview panel is closed.
  • Neos.MenuPanelOpened When the menu panel is opened.
  • Neos.MenuPanelClosed When the menu panel is closed.
  • Neos.FullScreenModeActivated When the backend switches to fullscreen mode.
  • Neos.FullScreenModeDeactivated When the backend leaves the fullscreen mode.

Example of interacting with the selected node element using the NodeSelected event.

document.addEventListener('Neos.NodeSelected', function(event) {
      var node = event.detail.node;
      if (event.detail.node.get('nodeType') === 'Acme:Demo') {
              console.log(node.getAttribute('title'), node.get('attributes.title'), node.$element);
      }
}, false);

Example of listening for the LayoutChanged event.

document.addEventListener('Neos.LayoutChanged', function(event) {
      // Do stuff
}, false);

Tip

As an alternative to using the LayoutChanged event, listening to transition events on the body can be done.

Example (using jQuery):

$('body').on('webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd', function() {
    // Do stuff
});

Backend API

The Neos backend exposes certain functions in a JavaScript API. These can be helpful to customize the editing experience for special elements.

  • Typo3Neos.Content.reloadPage() Reload the current page in the content module.

Rendering special formats (CSV, JSON, XML, …)

Rendering an RSS feed as XML or a document in a different format than HTML is possible by configuring a new route and adding a TypoScript path that renders the format.

Let’s have a look at an example that introduce a vcard format to render an imaginary Person document node type.

Routing

Configuration/Routes.yaml in your site package:

-
        name: 'Neos :: Frontend :: Document node with vCard format'
        uriPattern: '{node}.vcf'
        defaults:
                '@package': TYPO3.Neos
                '@controller': Frontend\Node
                '@action': show
                '@format': vcard
        routeParts:
                node:
                        handler: TYPO3\Neos\Routing\FrontendNodeRoutePartHandlerInterface
        appendExceedingArguments: true

This will register a new route to nodes with the vcard format. URIs with that format will get an .vcf extension.

Global Configuration/Routes.yaml (before the Neos subroutes):

##
# Site package subroutes

-
  name: 'MyPackage'
  uriPattern: '<MyPackageSubroutes>'
  subRoutes:
        'MyPackageSubroutes':
          package: 'My.Package'

##
# Neos subroutes
# ...

This will add the new route from the site package before the Neos subroutes.

TypoScript

The root case in the default TypoScript will render every format that is different from html by rendering a path with the format value.

Root.ts2:

# Define a path for rendering the vcard format
vcard = TYPO3.TypoScript:Case {
        person {
                condition = ${q(node).is('[instanceof My.Package:Person]')}
                type = 'My.Package:Person.Vcard'
        }
}

# Define a prototype to render a Person document as a vcard
prototype(My.Package:Person.Vcard) < prototype(TYPO3.TypoScript:Http.Message) {
        # Set the Content-Type header
        httpResponseHead {
                headers.Content-Type = 'text/x-vcard;charset=utf-8'
        }
        content = My.Package:Person {
                templatePath = 'resource://My.Package/Private/Templates/NodeTypes/Person.Vcard.html'
                # Set additional variables for the template
        }
}

Writing Tests For Neos

Testing and quality assurance documentation for Neos.

Behat tests for Neos

Setting up Neos for running Behat tests

The Neos package contains a growing suite of Behat tests which you should take into account while fixing bugs or adding new features. Please note that running these tests require that the Neos demo site package (Neos.Demo) is installed and activated.

Install Behat for the base distribution

Behat is installed in a separate folder and has a custom composer root file. To install Behat run the following composer command in FLOW_ROOT/Build/Behat:

cd Build/Behat
composer install

A special package Flowpack.Behat is used to integrate Flow with Behat and is installed if the base distribution was installed with composer install –dev.

Create configuration for subcontexts

Behat needs two special Flow contexts, Development/Behat and Testing/Behat.

  • The context Development/Behat should be mounted as a separate virtual host and is used by Behat to do the actual HTTP requests.
  • The context Testing/Behat is used inside the Behat feature context to set up test data and reset the database after each scenario.

These contexts should share the same database to work properly. Make sure to create a new database for the Behat tests since all the data will be removed after each scenario.

FLOW_ROOT/Configuration/Development/Behat/Settings.yaml:

TYPO3:
  Flow:
    persistence:
      backendOptions:
        dbname: 'neos_testing_behat'

FLOW_ROOT/Configuration/Testing/Behat/Settings.yaml:

TYPO3:
  Flow:
    persistence:
      backendOptions:
        dbname: 'neos_testing_behat'
        driver: pdo_mysql
        user: ''
        password: ''

Example virtual host configuration for Apache:

<VirtualHost *:80>
        DocumentRoot "FLOW_ROOT/Web"
        ServerName neos.behat.test
        SetEnv FLOW_CONTEXT Development/Behat
</VirtualHost>
Configure Behat

The Behat tests for Neos are shipped inside the TYPO3.Neos package in the folder Tests/Behavior. Behat uses a configuration file distributed with Neos, behat.yml.dist, or a local version, behat.yml. To run the tests, Behat needs a base URI pointing to the special virtual host running with the Development/Behat context. To set a custom base URI the default file should be copied and customized:

cd Packages/Application/TYPO3.Neos/Tests/Behavior
cp behat.yml.dist behat.yml
# Edit file behat.yml

Customized behat.yml:

default:
  paths:
    features: Features
    bootstrap: %behat.paths.features%/Bootstrap
  extensions:
    Behat\MinkExtension\Extension:
      files_path: features/Resources
      show_cmd: 'open %s'
      goutte: ~
      selenium2: ~

      base_url: http://neos.behat.test/
Selenium

Some tests require a running Selenium server for testing browser advanced interaction and JavaScript. Selenium Server can be downloaded at http://docs.seleniumhq.org/download/ and started with:

java -jar selenium-server-standalone-2.x.0.jar

If using Saucelabs, you do not need your own Selenium setup.

Running Behat tests

Behat tests can be run from the Flow root folder with the bin/behat command by specifying the Behat configuration file:

bin/behat -c Packages/Application/TYPO3.Neos/Tests/Behavior/behat.yml

In case the executable file bin/behat is missing, create a symlink by running the following command in FLOW_ROOT/bin:

ln -s ../Build/Behat/vendor/behat/behat/bin/behat

Tip

You might want to warmup the cache before you start the test. Otherwise the tests might fail due to a timeout. You can do that with FLOW_CONTEXT=Development/Behat ./flow flow:cache:warmup.

Debugging
  • Make sure to use a new database and configure the same databse for Development/Behat and Testing/Behat
  • Run Behat with the -v option to get more information about errors and failed tests
  • A failed step can be inspected by inserting “Then show last response” in the .feature definition
Run Behat tests on several browsers using Saucelabs

Note

Make sure that your Behat version is uptodate. Otherwise the saucelabs connection won’t work. The behat/mink-extension need to be at least version 1.3.

Saucelabs (http://saucelabs.com) provides a VM infrastructure you can use to run your selenium tests on.

Using this infrastructure you can run the @javascript tagged tests on several Browsers and OSs autmatically without setting up your own selenium infrastructure.

To run Neos Behat tests with saucelabs you need to do the following steps.

Configure Behat

To talk to saucelabs you need to uncomment the following lines in the behat.yml and add your saucelabs username and access_key:

javascript_session: saucelabs
  saucelabs:
    username: <username>
    access_key: <access_key>

Tip

Saucelabs provides unlimited video time for TYPO3 core development. If you want to contribute to Neos by writing tests ask Christian Müller.

To make tests with more browsers than the default browser you need to tell saucelabs which browser, version and OS you want to test on. You can add several browsers, each in its own profile. There are a lot of browsers configured already in the saucelabsBrowsers.yml file. You can include that into your behat configuration:

imports:
  - saucelabsBrowsers.yml
Open a tunnel to saucelabs

If you want to run the tests on your local machine you need to open a tunnel to saucelabs. This can be easily done by downloading Sauce Connect at https://docs.saucelabs.com/reference/sauce-connect/ and follow the instructions to setup and start it.

Run Behat tests

A test with Internet Explorer 10 on Windows8 would look like this then:

bin/behat -c Packages/Application/TYPO3.Neos/Tests/Behavior/behat.yml --profile windows8-ie-10

You might just want to run the tests that need javascript on different browsers (all other tests won’t use a browser anyways). Limit the tests to the @javascript tagged to do so:

bin/behat -c Packages/Application/TYPO3.Neos/Tests/Behavior/behat.yml --tags javascript --profile windows8-ie-10

Note

The possible configuration settings for browsers can be found at https://saucelabs.com/docs/platforms. Choose “WebDriver” and “php” and click on the platform/browser combination you are interested in.

Inside of Neos

User Interface Development

These are the user interface development guidelines of Neos.

General User Interface Principles

The following principles serve as general guiding concepts throughout the whole Neos product.

Overall User Interface Goals

We have set up the following goals to strive for UI-wise:

  • Reliable editing
  • Predictable UI Behavior
  • Immediate feedback for the user
  • Built with the web - for the web

UI concepts should be evaluated against the above goals.

Technical guidelines / Goals

When implementing the user interface, we should follow these guidelines on a technical side:

  • Take the pragmatic approach
  • Augment the frontend website
  • No iFrame in the content module, generally no iFrames except for bigger modal dialogs
  • Browser support >= IE9; in the prototyping phase focus on Chrome / Firefox
  • No polling of data from the server!
  • A reload should always take you back to a safe state
CSS Guidelines

Overall Goal:

  • Be pragmatic! We strive for solutions which work out-of-the-box in 95% of the cases; and tell the integrator how to solve the other 5%. Thus, the integrator has to care to make his CSS work with Neos; we do not use a sandbox.

Implementation notes:

  • All CSS selectors should be fully lowercase, with - as separator. Example: neos-menu, neos-inspector
  • We use the neos- prefix
  • The integrator is never allowed to override neos-, typo3- and aloha-
  • The main UI elements have an ID, and a partial reset is used to give us predictable behavior inside them.
  • We use sass. To install, use +gem install sass compass+. Then, before modifying CSS, go to css/ and run +sass –compass –watch style.scss:style.css+. This will update style.css at every modification of style.scss.
  • We use r.js for generating the Includes-built.css file. The command used by the built server is r.js -o cssIn=Includes.css out=Includes-built.css
Z-Indexes

The Neos UI uses Z-Indexes starting at 10000.

Warning

TODO: Formulate some more about the usage of z-indexes.

Content Module Principles

In the Content Module, we directly render the frontend of the website, and then augment it with the Neos Content Editing User Interface.

Because of this, we do not control all CSS or javaScript which is included on the page; so we need some special guidelines to deal with that. These are listed on this page.

Naming of main UI parts

The following image shows the main UI parts of the content module and the names we use for them.

UI parts of the content module

UI parts of the content module

Content Module Architecture

The whole Content Module is built around the Aloha Blocks. Blocks are un-editable elements of a website, which are managed by Aloha. They can appear inside or outside editables, can be nested, and can appear either as inline element (<span>) or as block-level element(<div>).

Only one block is active at any given time. When a block is active, then all its parent blocks are selected. The block selection contains the active block as first element and all other selected blocks from innermost to outermost.

Most of the UI changes depending on the current block selection.

User Interface Updates on Selection Change

The following diagram shows how the UI is changing when the block selection changes:

UI Updates on selection change

UI Updates on selection change

  1. The neosintegration Aloha Plugin (located in alohaplugins/neosintegration/lib/neosintegration-plugin.js) hooks into the Aloha event which is triggered whenever the block selection changes. Whenever this event is triggered, it calls T3.Content.Model.BlockSelection.updateSelection().
  2. We need to wrap each Aloha Block with a Ember.js Block (later only called Block), so we can attach event listeners to it. This wrapping is done by the BlockManager
  3. The BlockManager either returns existing Ember.js Blocks (if the given Aloha Block has already been wrapped), or creates a new one.
  4. Then, the BlockSelection sets its content property, which the UI is bound to. Thus, all UI elements which depend on the current block selection are refreshed.
User Interface Updates updates on property change

When an attribute is modified through the property panel, the following happens:

How attributes are modified

How attributes are modified

WARNING: TODO: Document what happens when an editable is modified

Node Property Naming Conventions

TODO write some intro text

  1. Normal properties

    Those properties contain normal values like a title, date or other value. Serverside setting of the property is done using TYPO3CR Node::setProperty()

  2. Visibility / lifecycle properties

    These properties are prefixed using an underscore, like ‘_hidden’. Serverside setting of the property is done using TYPO3CR Node::set<UpperCamelCasePropertyname>()

  3. Neos internal properties

    These properties are prefixed with a double underscore, like __workspacename TODO: internal

Saving content

Saving is triggered using T3.Content.Model.Changes.save() and is very straight-forward. For now, we use ExtDirect to send things back to the server.

Displaying Modal Dialogs

WARNING: TODO - write this

  • REST architectural style
  • HTML snippets loaded via fixed URLs from server side
  • Return Commands (<a rel="typo3-...." />)
REST Server Side API

Most backend services which are currently used in the user interface are not RESTful. The goal is to migrate them, step by step, to a clean REST architecture.

Two services have been – partially – migrated: Nodes and ContentDimensions. We provide an HTML and a JSON based interface, roughly following HATEOAS concepts. Both formats a not yet part of the public API and we expect them to change as we gain more experience with the pros and cons of their structure.

URL /neos/service/nodes URL /neos/service/contentdimensions

Inspect the HTML output and the controller / template code for more information about the currently supported operations and arguments.

Backend Module Principles

For backend modules (that is, every module except the content area), we use the following guiding principles in addition to the already-existing principles:

  • It should be possible to write backend modules only with PHP, without JavaScript involved
  • Some features might be only available to the user if he has JavaScript enabled
  • In order to introduce rich behavior, use the technique of progressive enhancement
Progressive Enhancement

As we want to use progressive enhancement heavily, we need to define some rules as a basis for that.

First, you should always think about the non-javascript functionality, and develop the feature without JavaScript enabled. This helps to get the client-server communication function correctly.

For most parts, you should not rely at all on any server state, but instead use URI parameters to encode required state. This makes the server-side code a lot easier and progressive enhancement more predictable.

Furthermore, if you reload certain parts of the user interface using AJAX, make sure to always update the browser’s URI using History Management: In case there is an error, the user can just re-load the page and will get pretty much the same User Interface state. This fulfills our UI goal of “predictable UI behavior”.

Connecting JavaScript code to the HTML content

In order to connect JavaScript code to HTML content, we (of course) rely on CSS selectors for finding the correct DOM nodes. However, we do not want to use CSS class attributes, as they change more frequently. Instead, we’d like to use special data-attributes to connect the JavaScript code to the user interface.

Note

In a nutshell:

  • CSS classes are used for the visible styling only
  • HTML5 Data Attributes are used for connecting the JavaScript code to HTML

We use the following data attributes for that:

  • data-area is used to search for DOM nodes, for later usage in JavaScript.

    As an example, use <div class="foo" data-area="actionBar"></div> in the HTML and match it using $('[data-area=actionBar]') in JavaScript.

  • data-json is used for transferring server-side state to the JavaScript as JSON.

    Example: We need the full URI parameters which have been used for the current rendering as array/object on the client side. Thus, the server side stores them inside <div style="display:none" data-json="uriParameters">{foo: 'bar'}</div>.

    The JavaScript code then accesses them at a central place using JSON.parse($('[data-json=uriParameters]').text()) and makes them available using some public API.

  • data-type is used to mark that certain parts of the website contain a client-side template language like handlebars.

    As an example for the action bar, we use the following code here:

      <button>
         Edit
         <span class="js" data-type="handlebars">
            {{#if multipleSelectionActive}} {{numberOfSelectedElements}} elements{{/if}}
         </span>
      </button>
    
    Then, on the client side in JavaScript, we use the handlebars template accordingly.
    
Adjusting the UI if JavaScript is (in-)active

Often, you want to hide or show some controls depending on whether JavaScript is enabled or disabled. By default, every DOM element is visible no matter whether JavaScript is enabled or not.

If you want to show a DOM element only if JavaScript is enabled, use the CSS class js.

If you want to show a DOM element only if JavaScript is disabled, use the CSS class nojs.

JavaScript Style Guide

Code Conventions
  • We use only the TAB character for indentation.
  • We use UpperCamelCase for class names, and lowerCamelCase for method and property names.
  • Methods and properties that begin with an underscore (_) are private.
  • Variables which contain jQuery elements should be named like $element, starting with a $. If it is a private jQuery element, prefix it with _$
  • We use that as a name for a closure reference to this, but try to avoid it if there’s the possibility of scope binding. Unfortunately jQuery’s event handlers do not allow easy scope binding.
Code Documentation

TODO: still determine this.

RequireJS module skeleton

All JavaScript files are RequireJS modules. They should follow this structure:

WARNING: still has to be done and discussed

<javascript> TODO </javascript>

Public API, Private methods and attributes

All methods and properties which are public API are marked with @api. The public API is supported for a longer period, and when a public API changes, this is clearly communicated in the Release Notes of a version.

On the contrary, we prefix private methods and attributes with an underscore. The user of an API should never override or call methods private methods as they are not meant for him to be overridden.

There’s also a type in between: methods which are not private but do not have a @api annotation. They can be safely overridden by the user, and he should not experience any unwanted behavior. Still, the names or functionality of these methods can change without notice between releases. In the long run, all of these methods should become part of the public API, as soon as they are proven in real life.

To sum it up, we have three types of methods/properties:

  • @api methods: Public API, the user of the object can rely on the functionality to be stable, changes in @api are clearly communicated
  • non-@api but also not private: The user can use it, but needs to be aware the method might still change.
  • private (prefixed with _): The user should never ever call or access this. Very strange things might happen.

Note

It is allowed to observe or bind to private properties within the Neos javascript code. This is because the property is not just meant as private object property, but as a non-api property.

When to use a new file

JavaScript files can become pretty large, so there should be a point to create a new file. Having just one class per file would be too much though, as this would end up in possibly hundreds of files, from which a lot will just have 20 lines of code.

As we use requirejs for loading dependencies we came up with the following guidelines for creating a new file:

  • Classes using a template include using the !text plugin should be in a separate file
  • If a class is extended by another class, then it should be in a separate file so it can be easily loaded as dependency
  • If a class is huge, and affecting readability of the definition file, then it should be moved to a single file
  • It has preference to keep classes grouped together, so classes with just a few lines stay grouped together, so if none of the above is true the classes stays in the main file.

Ember.JS Tips & Tricks

Dealing with classes and objects
  • Always extend from Ember.Object (or a subclass)
  • Extension is done using Ember.Object.extend({...})
  • Never use new to instantiate new objects. Instead, use TheObject.create(...)
  • All objects have generic set(key, value) and get(key) methods, which should be used under all circumstances!

The following example shows this:

var Foo = Ember.Object.extend({
        someValue: 'hello',
        myMethod: function() {
                alert(this.get('someValue'));
        }
});

var fooInstance = Foo.create({
        someValue: 'world'
});
fooInstance.myMethod(); // outputs "world"

Inheritance can be used just as in PHP, since Emberjs binds a special ._super() function for every method call (in fact the function is wrapped to create this special _super method). So calling the current method of the superclass can be done without specifying the superclass and method name.

var Foo = Ember.Object.extend({
        greet: function(name) {
                return 'Hello, ' + name;
        }
});
var Bar = Foo.extend({
        greet: function(name) {
                return 'Aloha and ' + this._super(name);
        }
});

Bar.create().greet('Neos'); // outputs "Aloha and Hello, Neos"
Data Binding tips and tricks

To create a computed property, implement it as function and append +.property()+:

var Foo = Ember.Object.extend({
        someComputedValue: function() {
                return "myMethod";
        }.property()
});

If your computed property reads other values, specify the dependent values as parameters to property(). If the computed property is deterministic and depends only on the dependant values, it should be marked further with .cacheable().

var Foo = Ember.Object.extend({
        name: 'world',
        greeting: function() {
                return "Hello " + this.attr('name');
        }.property('name').cacheable()

});

Now, every time name changes, the system re-evaluates greeting.

Note

Forgetting .cacheable() can have severe performance penalties and result in circular loops, in worst case freezing the browser completely.

You can also use a getter / setter on a property, if you do this it’s extremely important to return the value of the property in the setter method.

var Foo = Ember.Object.extend({
        firstName: null,
        lastName: null,

        fullName: function(key, value) {
                if (arguments.length === 1) {
                        return this.get('firstName') + ' ' + this.get('lastName');
                } else {
                        var parts = value.split(' ');
                        this.set('firstName', parts[0]);
                        this.set('lastName', parts[1]);

                        return value;
                }
        }.property('firstName', 'lastName').cacheable()
});
Observe changes

To react on changes of properties in models or views (or any other class extending Ember.Observable), a method marked as an observer can be used. Call .observes('propertyName') on a private method to be notified whenever a property changes.

var Foo = Ember.Object.extend({
        name: 'world',
        _nameDidChange: function() {
                console.log('name changed to', this.get('name'));
        }.observes('name')
});

Translating the user interface

Default Language

The availableLanguages are defined in Packages/Application/TYPO3.Neos/Configuration/Settings.yaml.

You may override the default language of your installation in Configuration/Settings.yaml:

TYPO3:
  Neos:
    userInterface:
      defaultLanguage: 'en'
Label Scrambling

To help you find labels in the Neos editor interface that you still need to translate, you can use the language label scrambling setting in your yaml file. This will replace all translations by a string consisting of only # characters with the same length as the actual translated label. With this setting enabled every still readable string in the backend is either content or non-translated.

TYPO3:
  Neos:
    userInterface:
      scrambleTranslatedLabels: TRUE

Note

The translation labels used in the javascript ui are parsed to a big json file. While changing xliff files this cached should be flushed, but still it can turn out useful to disable this cache. You can do so by using the following snippet in your Caches.yaml

TYPO3_Neos_XliffToJsonTranslations:
  backend: TYPO3\Flow\Cache\Backend\NullBackend

References

Mostly autogenerated documentation for ViewHelpers, EelHelpers, Typoscript etc. from all Packages that are in a default (Demo Package) setup.

Property Editor Reference

For each property which is defined in NodeTypes.yaml, the editor inside the Neos inspector can be customized using various options. Here follows the reference for each property type.

Property Type: boolean BooleanEditor – Checkbox editor

A boolean value is rendered using a checkbox in the inspector:

'isActive'
  type: boolean
  ui:
    label: 'is active'
    inspector:
      group: 'document'

Options Reference:

disabled (boolean)
HTML disabled property. If TRUE, disable this checkbox.

Property Type: string TextFieldEditor – Single-line Text Editor (default)

Example:

subtitle:
  type: string
  ui:
    label: 'Subtitle'
    help:
      message: 'Enter some help text for the editors here. The text will be shown via click.'
    inspector:
      group: 'document'
      editorOptions:
        placeholder: 'Enter subtitle here'
        maxlength: 20

Options Reference:

placeholder (string)
HTML5 placeholder property, which is shown if the text field is empty.
disabled (boolean)
HTML disabled property. If TRUE, disable this textfield.
maxlength (integer)
HTML maxlength property. Maximum number of characters allowed to be entered.
readonly (boolean)
HTML readonly property. If TRUE, this field is cannot be written to.
form (optional)
HTML5 form property.
selectionDirection (optional)
HTML5 selectionDirection property.
spellcheck (optional)
HTML5 spellcheck property.
required (boolean)
HTML5 required property. If TRUE, input is required.
title (boolean)
HTML title property.
autocapitalize (boolean)
Custom HTML autocapitalize property.
autocorrect (boolean)
Custom HTML autocorrect property.

Property Type: string TextAreaEditor – Multi-line Text Editor

In case the text input should span multiple lines, a TextAreaEditor should be used as follows:

'description':
    type: 'string'
    ui:
      label: 'Description'
      inspector:
        group: 'document'
        editor: 'TYPO3.Neos/Inspector/Editors/TextAreaEditor'
        editorOptions:
          rows: 7

Options Reference:

rows (integer)
Number of lines this textarea should have; Default 5.

** and all options from Text Field Editor – see above**

Property Type: string CodeEditor – Full-Screen Code Editor

In case a lot of space is needed for the text (f.e. for HTML source code), a CodeEditor can be used:

'source':
    type: 'string'
    ui:
      label: 'Source'
      inspector:
        group: 'document'
        editor: 'TYPO3.Neos/Inspector/Editors/CodeEditor'

Furthermore, the button label can be adjusted by specifying buttonLabel. Furthermore, the highlighting mode can be customized, which is helpful for editing markdown and similar contents:

'markdown':
    type: 'string'
    ui:
      label: 'Markdown'
      inspector:
        group: 'document'
        editor: 'TYPO3.Neos/Inspector/Editors/CodeEditor'
        editorOptions:
          buttonLabel: 'Edit Markdown'
          highlightingMode: 'text/plain'

Options Reference:

buttonLabel (string)
label of the button which is used to open the full-screen editor. Default Edit code.
highlightingMode (string)
CodeMirror highlighting mode to use. These formats are support by default: text/plain, text/xml, text/html, text/css, text/javascript. If other highlighting modes shall be used, they must be loaded beforehand using custom JS code. Default text/html.

Property Type: string / array<string> SelectBoxEditor – Dropdown Select Editor

In case only fixed entries are allowed to be chosen a select box can be used - multiple selection is supported as well. The data for populating the select box can be fetched from a fixed set of entries defined in YAML or a datasource. The most important option is called values, containing the choices which can be made. If wanted, an icon can be displayed for each choice by setting the icon class appropriately.

Basic Example – simple select box:

targetMode:
  type: string
  defaultValue: 'firstChildNode'
  ui:
    label: 'Target mode'
    inspector:
      group: 'document'
      editor: 'TYPO3.Neos/Inspector/Editors/SelectBoxEditor'
      editorOptions:
        values:
          firstChildNode:
            label: 'First child node'
            icon: 'icon-legal'
          parentNode:
            label: 'Parent node'
            icon: 'icon-fire'
          selectedTarget:
            label: 'Selected target'

If the selection list should be grouped, this can be done by setting the group key of each individual value:

country:
  type: string
  ui:
    label: 'Country'
    inspector:
      group: 'document'
      editor: 'TYPO3.Neos/Inspector/Editors/SelectBoxEditor'
      editorOptions:
        values:
          italy:
            label: 'Italy'
            group: 'Southern Europe'
          austria:
            label: 'Austria'
            group: 'Central Europe'
          germany:
            label: 'Germany'
            group: 'Central Europe'

Furthermore, multiple selection is also possible, by setting multiple to TRUE, which is automatically set for properties of type array. If an empty value is allowed as well, allowEmpty should be set to TRUE and placeholder should be set to a helpful text:

styleOptions:
  type: array
  ui:
    label: 'Styling Options'
    inspector:
      group: 'document'
      editor: 'TYPO3.Neos/Inspector/Editors/SelectBoxEditor'
      editorOptions:

        # The next line is set automatically for type array
        # multiple: TRUE

        allowEmpty: TRUE
        placeholder: 'Select Styling Options'

        values:
          leftColumn:
            label: 'Show Left Column'
          rightColumn:
            label: 'Show Right Column'

Because selection options shall be fetched from server-side code frequently, the Select Box Editor contains support for so-called data sources, by setting a dataSourceIdentifier, or optionally a dataSourceUri. This helps to provide data to the editing interface without having to define routes, policies or a controller. You can provide an array of dataSourceAdditionalData that will be sent to the data source with each request, the key/value pairs can be accessed in the $arguments array passed to getData().

questions:
  ui:
    inspector:
      editor: 'Content/Inspector/Editors/SelectBoxEditor'
      editorOptions:
        dataSourceIdentifier: 'questions'
        # alternatively using a custom uri:
        # dataSourceUri: 'custom-route/end-point'
        dataSourceAdditionalData:
          apiKey: 'foo-bar-baz'

See Data sources for more details on implementing a data source based on Neos conventions. If you are using a data source to populate SelectBoxEditor instances it has to be matching the values option. Make sure you sort by group first, if using the grouping option.

Example for returning compatible data:

return array(
    array('value' => 'key', 'label' => 'Foo', 'group' => 'A', 'icon' => 'icon-key'),
    array('value' => 'fire', 'label' => 'Fire', 'group' => 'A', 'icon' => 'icon-fire'),
    array('value' => 'legal', 'label' => 'Legal', 'group' => 'B', 'icon' => 'icon-legal')
);

If you use the dataSourceUri option to connect to an arbitrary service, make sure the output of the data source is a JSON formatted array matching the following structure. Make sure you sort by group first, if using the grouping option.

Example for compatible data:

[{
  "value": "key",
  "label": "Key",
  "group": "A",
  "icon": "icon-key"
},
{
  "value": "fire",
  "label": "Fire",
  "group": "A",
  "icon": "icon-fire"
},
{
  "value": "legal",
  "label": "Legal",
  "group": "B",
  "icon": "icon-legal"
}]

Options Reference:

values (required array)

the list of values which can be chosen from

[valueKey]

label (required string)
label of this value.
group (string)
group of this value.
icon (string)
CSS icon class for this value.
allowEmpty (boolean)
if TRUE, it is allowed to choose an empty value.
placeholder (string)
placeholder text which is shown if nothing is selected. Only works if allowEmpty is TRUE. Default Choose.
multiple (boolean)
If TRUE, multi-selection is allowed. Default FALSE.
minimumResultsForSearch (integer)
The minimum amount of items in the select before showing a search box, if set to -1 the search box will never be shown.
dataSourceUri (string)
If set, this URI will be called for loading the options of the select field.
dataSourceIdentifier (string)
If set, a server-side data source will be called for loading the possible options of the select field.
dataSourceAdditionalData (array)
Key/value pairs that will be sent to the server-side data source with every request.

Property Type: integer TextFieldEditor

Example:

cropAfterCharacters:
  type: integer
  ui:
    label: 'Crop after characters'
    inspector:
      group: 'document'

Options Reference:

all TextFieldEditor options apply

Property Type: reference / references ReferenceEditor / ReferencesEditor – Reference Selection Editors

The most important option for the property type reference and references is nodeTypes, which allows to restrict the type of the target nodes which can be selected in the editor.

Example:

authors:
  type: references
  ui:
    label: 'Article Authors'
    inspector:
      group: 'document'
      editorOptions:
        nodeTypes: ['My.Website:Author']

Options Reference:

nodeTypes (array of strings)
List of node types which are allowed to be selected. By default, is set to TYPO3.Neos:Document, allowing only to choose other document nodes.
placeholder (string)
Placeholder text to be shown if nothing is selected
startingPoint (string)
The starting point (node path) for finding possible nodes to create a reference. This allows to search for nodes outside the current site. If not given, nodes will be searched for in the current site. For all nodes outside the current site the node path is shown instead of the url path.
threshold (number)
Minimum amount of characters which trigger a search. Default is set to 2.

Property Type: DateTime DateTimeEditor – Date & Time Selection Editor

The most important option for DateTime properties is the format, which is configured like in PHP, as the following examples show:

  • d-m-Y: 05-12-2014 – allows to set only the date
  • d-m-Y H:i: 05-12-2014 17:07 – allows to set date and time
  • H:i: 17:07 – allows to set only the time

Example:

publishingDate:
  type: DateTime
  defaultValue: 'today midnight'
  ui:
    label: 'Publishing Date'
    inspector:
      group: 'document'
      position: 10
      editorOptions:
        format: 'd.m.Y'

Options Reference:

format (required string)
The date format, a combination of y, Y, F, m, M, n, t, d, D, j, l, N, S, w, a, A, g, G, h, H, i, s. Default d-m-Y.
defaultValue (string)
Sets property value, when the node is created. Accepted values are whatever strtotime() can parse, but it works best with relative formats like tomorrow 09:00 etc. Use now to set current date and time.
placeholder (string)
The placeholder shown when no date is selected
minuteStep (integer)
The granularity on which a time can be selected. Example: If set to 30, only half-hour increments of time can be chosen. Default 5 minutes.

For the date format, these are the available placeholders:

  • year
    • y: A two digit representation of a year - Examples: 99 or 03
    • Y: A full numeric representation of a year, 4 digits - Examples: 1999 or 2003
  • month
    • F: A full textual representation of a month, such as January or March - January through December
    • m: Numeric representation of a month, with leading zeros - 01 through 12
    • M: A short textual representation of a month, three letters - Jan through Dec
    • n: Numeric representation of a month, without leading zeros - 1 through 12
    • t: Number of days in the given month - 28 through 31
  • day
    • d: Day of the month, 2 digits with leading zeros - 01 to 31
    • D: A textual representation of a day, three letters - Mon through Sun
    • j: Day of the month without leading zeros - 1 to 31
    • l: A full textual representation of the day of the week - Sunday through Saturday
    • N: ISO-8601 numeric representation of the day of the week - 1 (for Monday) through 7 (for Sunday)
    • S: English ordinal suffix for the day of the month, 2 characters - st, nd, rd or th.
    • w: Numeric representation of the day of the week - 0 (for Sunday) through 6 (for Saturday)
  • hour
    • a: Lowercase Ante meridiem and Post meridiem - am or pm
    • A: Uppercase Ante meridiem and Post meridiem - AM or PM
    • g: hour without leading zeros - 12-hour format - 1 through 12
    • G: hour without leading zeros - 24-hour format - 0 through 23
    • h: 12-hour format of an hour with leading zeros - 01 through 12
    • H: 24-hour format of an hour with leading zeros - 00 through 23
  • minute
    • i: minutes, 2 digits with leading zeros - 00 to 59
  • second
    • s: seconds, 2 digits with leading zeros - 00 through 59

Property Type: image (TYPO3\Media\Domain\Model\ImageInterface) ImageEditor – Image Selection/Upload Editor

For properties of type TYPO3\Media\Domain\Model\ImageInterface, an image editor is rendered. If you want cropping and resizing functionality, you need to set features.crop and features.resize to TRUE, as in the following example:

'teaserImage'
  type: 'TYPO3\Media\Domain\Model\ImageInterface'
  ui:
    label: 'Teaser Image'
    inspector:
      group: 'document'
      editorOptions:
        features:
          crop: TRUE
          resize: TRUE

If cropping is enabled, you might want to enforce a certain aspect ratio, which can be done by setting crop.aspectRatio.locked.width and crop.aspectRatio.locked.height. In the following example, the image format must be 16:9:

'teaserImage'
  type: 'TYPO3\Media\Domain\Model\ImageInterface'
  ui:
    label: 'Teaser Image'
    inspector:
      group: 'document'
      editorOptions:
        features:
          crop: TRUE
        crop:
          aspectRatio:
            locked:
              width: 16
              height: 9

If not locking the cropping to a specific ratio, a set of predefined ratios can be chosen by the user. Elements can be added or removed from this list underneath crop.aspectRatio.options. If the aspect ratio of the original image shall be added to the list, crop.aspectRatio.enableOriginal must be set to TRUE. If the user should be allowed to choose a custom aspect ratio, set crop.aspectRatio.allowCustom to TRUE:

'teaserImage'
  type: 'TYPO3\Media\Domain\Model\ImageInterface'
  ui:
    label: 'Teaser Image'
    inspector:
      group: 'document'
      editorOptions:
        features:
          crop: TRUE
        crop:
          aspectRatio:
            options:
              square:
                width: 1
                height: 1
                label: 'Square'
              fourFive:
                width: 4
                height: 5
              # disable this ratio (if it was defined in a supertype)
              fiveSeven: ~
            enableOriginal: TRUE
            allowCustom: TRUE

Options Reference:

maximumFileSize (string)
Set the maximum allowed file size to be uploaded. Accepts numeric or formatted string values, e.g. “204800” or “204800b” or “2kb”. Defaults to the maximum allowed upload size configured in php.ini

features

crop (boolean)
If TRUE, enable image cropping. Default TRUE.
resize (boolean)
If TRUE, enable image resizing. Default FALSE.
crop

crop-related options. Only relevant if features.crop is enabled.

aspectRatio

locked

Locks the aspect ratio to a specific width/height ratio

width (integer)
width of the aspect ratio which shall be enforced
height (integer)
height of the aspect ratio which shall be enforced
options

aspect-ratio presets. Only effective if locked is not set.

[presetIdentifier]

width (required integer)
the width of the aspect ratio preset
height (required integer)
the height of the aspect ratio preset
label (string)
a human-readable name of the aspect ratio preset
enableOriginal (boolean)
If TRUE, the image ratio of the original image can be chosen in the selector. Only effective if locked is not set. Default TRUE.
allowCustom (boolean)
If TRUE, a completely custom image ratio can be chosen. Only effective if locked is not set. Default TRUE.
defaultOption (string)
default aspect ratio option to be chosen if no cropping has been applied already.

Property Type: asset (TYPO3\Media\Domain\Model\Asset / array<TYPO3\Media\Domain\Model\Asset>) AssetEditor – File Selection Editor

If an asset, i.e. TYPO3\Media\Domain\Model\Asset, shall be uploaded or selected, the following configuration is an example:

'caseStudyPdf'
  type: 'TYPO3\Media\Domain\Model\Asset'
  ui:
    label: 'Case Study PDF'
    inspector:
      group: 'document'

Conversely, if multiple assets shall be uploaded, use array<TYPO3\Media\Domain\Model\Asset> as type:

'caseStudies'
  type: 'array<TYPO3\Media\Domain\Model\Asset>'
  ui:
    label: 'Case Study PDF'
    inspector:
      group: 'document'

Options Reference:

(no options)

Property Validation

The validators that can be assigned to properties in the node type configuration are used on properties that are edited via the inspector and are applied on the client-side only. The available validators can be found in the Neos package in Resources/Public/JavaScript/Shared/Validation:

  • AlphanumericValidator
  • CountValidator
  • DateTimeRangeValidator
  • DateTimeValidator
  • EmailAddressValidator
  • FloatValidator
  • IntegerValidator
  • LabelValidator
  • NotEmptyValidator
  • NumberRangeValidator
  • RegularExpressionValidator
  • StringLengthValidator
  • StringValidator
  • TextValidator
  • UuidValidator

The options are in sync with the Flow validators, so feel free to check the Flow documentation for details.

To apply options, just specify them like this:

someProperty:
  validation:
    'TYPO3.Neos/Validation/StringLengthValidator':
      minimum: 1
      maximum: 255
Extensibility

It is also possible to add Custom Editors and use Custom Validators.

View Helper Reference

Fluid ViewHelper Reference

This reference was automatically generated from code on 2016-06-07

f:alias

Declares new variables which are aliases of other variables. Takes a “map”-Parameter which is an associative array which defines the shorthand mapping.

The variables are only declared inside the <f:alias>…</f:alias>-tag. After the closing tag, all declared variables are removed again.

Implementation:TYPO3\Fluid\ViewHelpers\AliasViewHelper
Arguments
  • map (array): array that specifies which variables should be mapped to which alias
Examples

Single alias:

<f:alias map="{x: 'foo'}">{x}</f:alias>

Expected result:

foo

Multiple mappings:

<f:alias map="{x: foo.bar.baz, y: foo.bar.baz.name}">
  {x.name} or {y}
</f:alias>

Expected result:

[name] or [name]
depending on {foo.bar.baz}
f:base

View helper which creates a <base href=”…” /> tag. The Base URI is taken from the current request.

Implementation:TYPO3\Fluid\ViewHelpers\BaseViewHelper
Examples

Example:

<f:base />

Expected result:

<base href="http://yourdomain.tld/" />
(depending on your domain)
f:case

Case view helper that is only usable within the SwitchViewHelper.

Implementation:TYPO3\Fluid\ViewHelpers\CaseViewHelper
Arguments
  • value (mixed)
f:comment

This ViewHelper prevents rendering of any content inside the tag Note: Contents of the comment will still be parsed thus throwing an Exception if it contains syntax errors. You can put child nodes in CDATA tags to avoid this.

Implementation:TYPO3\Fluid\ViewHelpers\CommentViewHelper
Examples

Commenting out fluid code:

Before
<f:comment>
  This is completely hidden.
  <f:debug>This does not get rendered</f:debug>
</f:comment>
After

Expected result:

Before
After

Prevent parsing:

<f:comment><![CDATA[
 <f:some.invalid.syntax />
]]></f:comment>
f:count

This ViewHelper counts elements of the specified array or countable object.

Implementation:TYPO3\Fluid\ViewHelpers\CountViewHelper
Arguments
  • subject (array|Countable, optional): The array or Countable to be counted
Examples

Count array elements:

<f:count subject="{0:1, 1:2, 2:3, 3:4}" />

Expected result:

4

inline notation:

{objects -> f:count()}

Expected result:

10 (depending on the number of items in {objects})
f:cycle

This ViewHelper cycles through the specified values. This can be often used to specify CSS classes for example. Note: To achieve the “zebra class” effect in a loop you can also use the “iteration” argument of the for ViewHelper.

Implementation:TYPO3\Fluid\ViewHelpers\CycleViewHelper
Arguments
  • values (array): The array or object implementing ArrayAccess (for example SplObjectStorage) to iterated over
  • as (string): The name of the iteration variable
Examples

Simple:

<f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo"><f:cycle values="{0: 'foo', 1: 'bar', 2: 'baz'}" as="cycle">{cycle}</f:cycle></f:for>

Expected result:

foobarbazfoo

Alternating CSS class:

<ul>
  <f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo">
    <f:cycle values="{0: 'odd', 1: 'even'}" as="zebraClass">
      <li class="{zebraClass}">{foo}</li>
    </f:cycle>
  </f:for>
</ul>

Expected result:

<ul>
  <li class="odd">1</li>
  <li class="even">2</li>
  <li class="odd">3</li>
  <li class="even">4</li>
</ul>
f:debug

View helper that outputs its child nodes with TYPO3Flowvar_dump()

Implementation:TYPO3\Fluid\ViewHelpers\DebugViewHelper
Arguments
  • title (string, optional)
  • typeOnly (boolean, optional): Whether only the type should be returned instead of the whole chain.
Examples

inline notation and custom title:

{object -> f:debug(title: 'Custom title')}

Expected result:

all properties of {object} nicely highlighted (with custom title)

only output the type:

{object -> f:debug(typeOnly: true)}

Expected result:

the type or class name of {object}
f:defaultCase

A view helper which specifies the “default” case when used within the SwitchViewHelper.

Implementation:TYPO3\Fluid\ViewHelpers\DefaultCaseViewHelper
f:else

Else-Branch of a condition. Only has an effect inside of “If”. See the If-ViewHelper for documentation.

Implementation:TYPO3\Fluid\ViewHelpers\ElseViewHelper
Examples

Output content if condition is not met:

<f:if condition="{someCondition}">
  <f:else>
    condition was not true
  </f:else>
</f:if>

Expected result:

Everything inside the "else" tag is displayed if the condition evaluates to FALSE.
Otherwise nothing is outputted in this example.
f:flashMessages

View helper which renders the flash messages (if there are any) as an unsorted list.

Implementation:TYPO3\Fluid\ViewHelpers\FlashMessagesViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • as (string, optional): The name of the current flashMessage variable for rendering inside
  • severity (string, optional): severity of the messages (One of the TYPO3FlowErrorMessage::SEVERITY_* constants)
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Simple:

<f:flashMessages />

Expected result:

<ul>
  <li class="flashmessages-ok">Some Default Message</li>
  <li class="flashmessages-warning">Some Warning Message</li>
</ul>

Output with css class:

<f:flashMessages class="specialClass" />

Expected result:

<ul class="specialClass">
  <li class="specialClass-ok">Default Message</li>
  <li class="specialClass-notice"><h3>Some notice message</h3>With message title</li>
</ul>

Output flash messages as a list, with arguments and filtered by a severity:

<f:flashMessages severity="Warning" as="flashMessages">
        <dl class="messages">
        <f:for each="{flashMessages}" as="flashMessage">
                <dt>{flashMessage.code}</dt>
                <dd>{flashMessage}</dd>
        </f:for>
        </dl>
</f:flashMessages>

Expected result:

<dl class="messages">
        <dt>1013</dt>
        <dd>Some Warning Message.</dd>
</dl>
f:for

Loop view helper which can be used to iterate over arrays. Implements what a basic foreach()-PHP-method does.

Implementation:TYPO3\Fluid\ViewHelpers\ForViewHelper
Arguments
  • each (array): The array or SplObjectStorage to iterated over
  • as (string): The name of the iteration variable
  • key (string, optional): The name of the variable to store the current array key
  • reverse (boolean, optional): If enabled, the iterator will start with the last element and proceed reversely
  • iteration (string, optional): The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)
Examples

Simple Loop:

<f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo">{foo}</f:for>

Expected result:

1234

Output array key:

<ul>
  <f:for each="{fruit1: 'apple', fruit2: 'pear', fruit3: 'banana', fruit4: 'cherry'}" as="fruit" key="label">
    <li>{label}: {fruit}</li>
  </f:for>
</ul>

Expected result:

<ul>
  <li>fruit1: apple</li>
  <li>fruit2: pear</li>
  <li>fruit3: banana</li>
  <li>fruit4: cherry</li>
</ul>

Iteration information:

<ul>
  <f:for each="{0:1, 1:2, 2:3, 3:4}" as="foo" iteration="fooIterator">
    <li>Index: {fooIterator.index} Cycle: {fooIterator.cycle} Total: {fooIterator.total}{f:if(condition: fooIterator.isEven, then: ' Even')}{f:if(condition: fooIterator.isOdd, then: ' Odd')}{f:if(condition: fooIterator.isFirst, then: ' First')}{f:if(condition: fooIterator.isLast, then: ' Last')}</li>
  </f:for>
</ul>

Expected result:

<ul>
  <li>Index: 0 Cycle: 1 Total: 4 Odd First</li>
  <li>Index: 1 Cycle: 2 Total: 4 Even</li>
  <li>Index: 2 Cycle: 3 Total: 4 Odd</li>
  <li>Index: 3 Cycle: 4 Total: 4 Even Last</li>
</ul>
f:form

Used to output an HTML <form> tag which is targeted at the specified action, in the current controller and package.

Implementation:TYPO3\Fluid\ViewHelpers\FormViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • action (string, optional): target action
  • arguments (array, optional): additional arguments
  • controller (string, optional): name of target controller
  • package (string, optional): name of target package
  • subpackage (string, optional): name of target subpackage
  • object (mixed, optional): object to use for the form. Use in conjunction with the “property” attribute on the sub tags
  • section (string, optional): The anchor to be added to the action URI (only active if $actionUri is not set)
  • format (string, optional): The requested format (e.g. “.html”) of the target page (only active if $actionUri is not set)
  • additionalParams (array, optional): additional action URI query parameters that won’t be prefixed like $arguments (overrule $arguments) (only active if $actionUri is not set)
  • absolute (boolean, optional): If set, an absolute action URI is rendered (only active if $actionUri is not set)
  • addQueryString (boolean, optional): If set, the current query parameters will be kept in the action URI (only active if $actionUri is not set)
  • argumentsToBeExcludedFromQueryString (array, optional): arguments to be removed from the action URI. Only active if $addQueryString = TRUE and $actionUri is not set
  • fieldNamePrefix (string, optional): Prefix that will be added to all field names within this form
  • actionUri (string, optional): can be used to overwrite the “action” attribute of the form tag
  • objectName (string, optional): name of the object that is bound to this form. If this argument is not specified, the name attribute of this form is used to determine the FormObjectName
  • useParentRequest (boolean, optional): If set, the parent Request will be used instead ob the current one
  • enctype (string, optional): MIME type with which the form is submitted
  • method (string, optional): Transfer type (GET or POST)
  • name (string, optional): Name of form
  • onreset (string, optional): JavaScript: On reset of the form
  • onsubmit (string, optional): JavaScript: On submit of the form
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Basic usage, POST method:

<f:form action="...">...</f:form>

Expected result:

<form action="...">...</form>

Basic usage, GET method:

<f:form action="..." method="get">...</f:form>

Expected result:

<form method="GET" action="...">...</form>

Form with a sepcified encoding type:

<f:form action=".." controller="..." package="..." enctype="multipart/form-data">...</f:form>

Expected result:

<form enctype="multipart/form-data" action="...">...</form>

Binding a domain object to a form:

<f:form action="..." name="customer" object="{customer}">
  <f:form.hidden property="id" />
  <f:form.textfield property="name" />
</f:form>

Expected result:

A form where the value of {customer.name} is automatically inserted inside the textbox; the name of the textbox is
set to match the property name.
f:form.button

Creates a button.

Implementation:TYPO3\Fluid\ViewHelpers\Form\ButtonViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • type (string, optional): Specifies the type of button (e.g. “button”, “reset” or “submit”)
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • autofocus (string, optional): Specifies that a button should automatically get focus when the page loads
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • form (string, optional): Specifies one or more forms the button belongs to
  • formaction (string, optional): Specifies where to send the form-data when a form is submitted. Only for type=”submit”
  • formenctype (string, optional): Specifies how form-data should be encoded before sending it to a server. Only for type=”submit” (e.g. “application/x-www-form-urlencoded”, “multipart/form-data” or “text/plain”)
  • formmethod (string, optional): Specifies how to send the form-data (which HTTP method to use). Only for type=”submit” (e.g. “get” or “post”)
  • formnovalidate (string, optional): Specifies that the form-data should not be validated on submission. Only for type=”submit”
  • formtarget (string, optional): Specifies where to display the response after submitting the form. Only for type=”submit” (e.g. “_blank”, “_self”, “_parent”, “_top”, “framename”)
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Defaults:

<f:form.button>Send Mail</f:form.button>

Expected result:

<button type="submit" name="" value="">Send Mail</button>

Disabled cancel button with some HTML5 attributes:

<f:form.button type="reset" name="buttonName" value="buttonValue" disabled="disabled" formmethod="post" formnovalidate="formnovalidate">Cancel</f:form.button>

Expected result:

<button disabled="disabled" formmethod="post" formnovalidate="formnovalidate" type="reset" name="myForm[buttonName]" value="buttonValue">Cancel</button>
f:form.checkbox

View Helper which creates a simple checkbox (<input type=”checkbox”>).

Implementation:TYPO3\Fluid\ViewHelpers\Form\CheckboxViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • checked (boolean, optional): Specifies that the input element should be preselected
  • multiple (boolean, optional): Specifies whether this checkbox belongs to a multivalue (is part of a checkbox group)
  • name (string, optional): Name of input tag
  • value (string): Value of input tag. Required for checkboxes
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.checkbox name="myCheckBox" value="someValue" />

Expected result:

<input type="checkbox" name="myCheckBox" value="someValue" />

Preselect:

<f:form.checkbox name="myCheckBox" value="someValue" checked="{object.value} == 5" />

Expected result:

<input type="checkbox" name="myCheckBox" value="someValue" checked="checked" />
(depending on $object)

Bind to object property:

<f:form.checkbox property="interests" value="TYPO3" />

Expected result:

<input type="checkbox" name="user[interests][]" value="TYPO3" checked="checked" />
(depending on property "interests")
f:form.hidden

Renders an <input type=”hidden” …> tag.

Implementation:TYPO3\Fluid\ViewHelpers\Form\HiddenViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.hidden name="myHiddenValue" value="42" />

Expected result:

<input type="hidden" name="myHiddenValue" value="42" />
f:form.password

View Helper which creates a simple Password Text Box (<input type=”password”>).

Implementation:TYPO3\Fluid\ViewHelpers\Form\PasswordViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • required (boolean, optional): If the field is required or not
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • maxlength (int, optional): The maxlength attribute of the input field (will not be validated)
  • readonly (string, optional): The readonly attribute of the input field
  • size (int, optional): The size of the input field
  • placeholder (string, optional): The placeholder of the input field
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.password name="myPassword" />

Expected result:

<input type="password" name="myPassword" value="default value" />
f:form.radio

View Helper which creates a simple radio button (<input type=”radio”>).

Implementation:TYPO3\Fluid\ViewHelpers\Form\RadioViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • checked (boolean, optional): Specifies that the input element should be preselected
  • name (string, optional): Name of input tag
  • value (string): Value of input tag. Required for radio buttons
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.radio name="myRadioButton" value="someValue" />

Expected result:

<input type="radio" name="myRadioButton" value="someValue" />

Preselect:

<f:form.radio name="myRadioButton" value="someValue" checked="{object.value} == 5" />

Expected result:

<input type="radio" name="myRadioButton" value="someValue" checked="checked" />
(depending on $object)

Bind to object property:

<f:form.radio property="newsletter" value="1" /> yes
<f:form.radio property="newsletter" value="0" /> no

Expected result:

<input type="radio" name="user[newsletter]" value="1" checked="checked" /> yes
<input type="radio" name="user[newsletter]" value="0" /> no
(depending on property "newsletter")
f:form.select

This ViewHelper generates a <select> dropdown list for the use with a form.

Basic usage

The most straightforward way is to supply an associative array as the “options” parameter. The array key is used as option key, and the array value is used as human-readable name.

To pre-select a value, set “value” to the option key which should be selected. If the select box is a multi-select box (multiple=”true”), then “value” can be an array as well.

Usage on domain objects

If you want to output domain objects, you can just pass them as array into the “options” parameter. To define what domain object value should be used as option key, use the “optionValueField” variable. Same goes for optionLabelField. If neither is given, the Identifier (UUID/uid) and the __toString() method are tried as fallbacks.

If the optionValueField variable is set, the getter named after that value is used to retrieve the option key. If the optionLabelField variable is set, the getter named after that value is used to retrieve the option value.

If the prependOptionLabel variable is set, an option item is added in first position, bearing an empty string or - if specified - the value of the prependOptionValue variable as value.

In the example below, the userArray is an array of “User” domain objects, with no array key specified. Thus the method $user->getId() is called to retrieve the key, and $user->getFirstName() to retrieve the displayed value of each entry. The “value” property now expects a domain object, and tests for object equivalence.

Translation of select content

The ViewHelper can be given a “translate” argument with configuration on how to translate option labels. The array can have the following keys: - “by” defines if translation by message id or original label is to be used (“id” or “label”) - “using” defines if the option tag’s “value” or “label” should be used as translation input, defaults to “value” - “locale” defines the locale identifier to use, optional, defaults to current locale - “source” defines the translation source name, optional, defaults to “Main” - “package” defines the package key of the translation source, optional, defaults to current package - “prefix” defines a prefix to use for the message id – only works in combination with “by id”

Implementation:TYPO3\Fluid\ViewHelpers\Form\SelectViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
  • multiple (string, optional): if set, multiple select field
  • size (string, optional): Size of input field
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • options (array): Associative array with internal IDs as key, and the values are displayed in the select box
  • optionValueField (string, optional): If specified, will call the appropriate getter on each object to determine the value.
  • optionLabelField (string, optional): If specified, will call the appropriate getter on each object to determine the label.
  • sortByOptionLabel (boolean, optional): If true, List will be sorted by label.
  • selectAllByDefault (boolean, optional): If specified options are selected if none was set before.
  • errorClass (string, optional): CSS class to set if there are errors for this ViewHelper
  • translate (array, optional): Configures translation of ViewHelper output.
  • prependOptionLabel (string, optional): If specified, will provide an option at first position with the specified label.
  • prependOptionValue (string, optional): If specified, will provide an option at first position with the specified value. This argument is only respected if prependOptionLabel is set.
Examples

Basic usage:

<f:form.select name="paymentOptions" options="{payPal: 'PayPal International Services', visa: 'VISA Card'}" />

Expected result:

<select name="paymentOptions">
  <option value="payPal">PayPal International Services</option>
  <option value="visa">VISA Card</option>
</select>

Preselect a default value:

<f:form.select name="paymentOptions" options="{payPal: 'PayPal International Services', visa: 'VISA Card'}" value="visa" />

Expected result:

(Generates a dropdown box like above, except that "VISA Card" is selected.)

Use with domain objects:

<f:form.select name="users" options="{userArray}" optionValueField="id" optionLabelField="firstName" />

Expected result:

(Generates a dropdown box, using ids and first names of the User instances.)

Prepend a fixed option:

<f:form.select property="salutation" options="{salutations}" prependOptionLabel="- select one -" />

Expected result:

<select name="salutation">
  <option value="">- select one -</option>
  <option value="Mr">Mr</option>
  <option value="Mrs">Mrs</option>
  <option value="Ms">Ms</option>
</select>
(depending on variable "salutations")

Label translation:

<f:form.select name="paymentOption" options="{payPal: 'PayPal International Services', visa: 'VISA Card'}" translate="{by: 'id'}" />

Expected result:

(Generates a dropdown box and uses the values "payPal" and "visa" to look up
translations for those ids in the current package's "Main" XLIFF file.)

Label translation usign a prefix:

<f:form.select name="paymentOption" options="{payPal: 'PayPal International Services', visa: 'VISA Card'}" translate="{by: 'id', prefix: 'shop.paymentOptions.'}" />

Expected result:

(Generates a dropdown box and uses the values "shop.paymentOptions.payPal"
and "shop.paymentOptions.visa" to look up translations for those ids in the
current package's "Main" XLIFF file.)
f:form.submit

Creates a submit button.

Implementation:TYPO3\Fluid\ViewHelpers\Form\SubmitViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Defaults:

<f:form.submit value="Send Mail" />

Expected result:

<input type="submit" />

Dummy content for template preview:

<f:form.submit name="mySubmit" value="Send Mail"><button>dummy button</button></f:form.submit>

Expected result:

<input type="submit" name="mySubmit" value="Send Mail" />
f:form.textarea

Textarea view helper. The value of the text area needs to be set via the “value” attribute, as with all other form ViewHelpers.

Implementation:TYPO3\Fluid\ViewHelpers\Form\TextareaViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • rows (int, optional): The number of rows of a text area
  • cols (int, optional): The number of columns of a text area
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • placeholder (string, optional): The placeholder of the textarea
  • autofocus (string, optional): Specifies that a text area should automatically get focus when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • required (boolean, optional): If the field should be marked as required or not
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.textarea name="myTextArea" value="This is shown inside the textarea" />

Expected result:

<textarea name="myTextArea">This is shown inside the textarea</textarea>
f:form.textfield

View Helper which creates a text field (<input type=”text”>).

Implementation:TYPO3\Fluid\ViewHelpers\Form\TextfieldViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • required (boolean, optional): If the field is required or not
  • type (string, optional): The field type, e.g. “text”, “email”, “url” etc.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • maxlength (int, optional): The maxlength attribute of the input field (will not be validated)
  • readonly (string, optional): The readonly attribute of the input field
  • size (int, optional): The size of the input field
  • placeholder (string, optional): The placeholder of the input field
  • autofocus (string, optional): Specifies that a input field should automatically get focus when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.textfield name="myTextBox" value="default value" />

Expected result:

<input type="text" name="myTextBox" value="default value" />
f:form.upload

A view helper which generates an <input type=”file”> HTML element. Make sure to set enctype=”multipart/form-data” on the form!

If a file has been uploaded successfully and the form is re-displayed due to validation errors, this ViewHelper will render hidden fields that contain the previously generated resource so you won’t have to upload the file again.

You can use a separate ViewHelper to display previously uploaded resources in order to remove/replace them.

Implementation:TYPO3\Fluid\ViewHelpers\Form\UploadViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • collection (string, optional): Name of the resource collection this file should be uploaded to
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<f:form.upload name="file" />

Expected result:

<input type="file" name="file" />

Multiple Uploads:

<f:form.upload property="attachments.0.originalResource" />
<f:form.upload property="attachments.1.originalResource" />

Expected result:

<input type="file" name="formObject[attachments][0][originalResource]">
<input type="file" name="formObject[attachments][0][originalResource]">

Default resource:

<f:form.upload name="file" value="{someDefaultResource}" />

Expected result:

<input type="hidden" name="file[originallySubmittedResource][__identity]" value="<someDefaultResource-UUID>" />
<input type="file" name="file" />

Specifying the resource collection for the new resource:

<f:form.upload name="file" collection="invoices"/>

Expected result:

<input type="file" name="yourInvoice" />
<input type="hidden" name="yourInvoice[__collectionName]" value="invoices" />
f:form.validationResults
Implementation:TYPO3\Fluid\ViewHelpers\Form\ValidationResultsViewHelper
Arguments
  • for (string, optional): The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.
  • as (string, optional): The name of the variable to store the current error
f:format.bytes

Formats an integer with a byte count into human-readable form.

Implementation:TYPO3\Fluid\ViewHelpers\Format\BytesViewHelper
Arguments
  • value (integer, optional): The incoming data to convert, or NULL if VH children should be used
  • decimals (integer, optional): The number of digits after the decimal point
  • decimalSeparator (string, optional): The decimal point character
  • thousandsSeparator (string, optional): The character for grouping the thousand digits
Examples

Defaults:

{fileSize -> f:format.bytes()}

Expected result:

123 KB
// depending on the value of {fileSize}

Defaults:

{fileSize -> f:format.bytes(decimals: 2, decimalSeparator: ',', thousandsSeparator: ',')}

Expected result:

1,023.00 B
// depending on the value of {fileSize}
f:format.case

Modifies the case of an input string to upper- or lowercase or capitalization. The default transformation will be uppercase as in mb_convert_case [1].

Possible modes are:

lower
Transforms the input string to its lowercase representation
upper
Transforms the input string to its uppercase representation
capital
Transforms the input string to its first letter upper-cased, i.e. capitalization
uncapital
Transforms the input string to its first letter lower-cased, i.e. uncapitalization
capitalWords
Transforms the input string to each containing word being capitalized

Note that the behavior will be the same as in the appropriate PHP function mb_convert_case [1]; especially regarding locale and multibyte behavior.

Implementation:TYPO3\Fluid\ViewHelpers\Format\CaseViewHelper
Arguments
  • value (string, optional): The input value. If not given, the evaluated child nodes will be used
  • mode (string, optional): The case to apply, must be one of this’ CASE_* constants. Defaults to uppercase application
f:format.crop

Use this view helper to crop the text between its opening and closing tags.

Implementation:TYPO3\Fluid\ViewHelpers\Format\CropViewHelper
Arguments
  • maxCharacters (integer): Place where to truncate the string
  • append (string, optional): What to append, if truncation happened
  • value (string, optional): The input value which should be cropped. If not set, the evaluated contents of the child nodes will be used
Examples

Defaults:

<f:format.crop maxCharacters="10">This is some very long text</f:format.crop>

Expected result:

This is so...

Custom suffix:

<f:format.crop maxCharacters="17" append=" [more]">This is some very long text</f:format.crop>

Expected result:

This is some very [more]

Inline notation:

<span title="Location: {user.city -> f:format.crop(maxCharacters: '12')}">John Doe</span>

Expected result:

<span title="Location: Newtownmount...">John Doe</span>
f:format.currency

Formats a given float to a currency representation.

Implementation:TYPO3\Fluid\ViewHelpers\Format\CurrencyViewHelper
Arguments
  • forceLocale (mixed, optional): Whether if, and what, Locale should be used. May be boolean, string or TYPO3FlowI18nLocale
  • currencySign (string, optional): (optional) The currency sign, eg $ or €.
  • decimalSeparator (string, optional): (optional) The separator for the decimal point.
  • thousandsSeparator (string, optional): (optional) The thousands separator.
Examples

Defaults:

<f:format.currency>123.456</f:format.currency>

Expected result:

123,46

All parameters:

<f:format.currency currencySign="$" decimalSeparator="." thousandsSeparator=",">54321</f:format.currency>

Expected result:

54,321.00 $

Inline notation:

{someNumber -> f:format.currency(thousandsSeparator: ',', currencySign: '€')}

Expected result:

54,321,00 
(depending on the value of {someNumber})

Inline notation with current locale used:

{someNumber -> f:format.currency(currencySign: '€', forceLocale: true)}

Expected result:

54.321,00 
(depending on the value of {someNumber} and the current locale)

Inline notation with specific locale used:

{someNumber -> f:format.currency(currencySign: 'EUR', forceLocale: 'de_DE')}

Expected result:

54.321,00 EUR
(depending on the value of {someNumber})
f:format.date

Formats a DateTime object.

Implementation:TYPO3\Fluid\ViewHelpers\Format\DateViewHelper
Arguments
  • forceLocale (mixed, optional): Whether if, and what, Locale should be used. May be boolean, string or TYPO3FlowI18nLocale
  • date (mixed, optional): either a DateTime object or a string that is accepted by DateTime constructor
  • format (string, optional): Format String which is taken to format the Date/Time if none of the locale options are set.
  • localeFormatType (string, optional): Whether to format (according to locale set in $forceLocale) date, time or datetime. Must be one of TYPO3FlowI18nCldrReaderDatesReader::FORMAT_TYPE_*’s constants.
  • localeFormatLength (string, optional): Format length if locale set in $forceLocale. Must be one of TYPO3FlowI18nCldrReaderDatesReader::FORMAT_LENGTH_*’s constants.
  • cldrFormat (string, optional): Format string in CLDR format (see http://cldr.unicode.org/translation/date-time)
Examples

Defaults:

<f:format.date>{dateObject}</f:format.date>

Expected result:

1980-12-13
(depending on the current date)

Custom date format:

<f:format.date format="H:i">{dateObject}</f:format.date>

Expected result:

01:23
(depending on the current time)

strtotime string:

<f:format.date format="d.m.Y - H:i:s">+1 week 2 days 4 hours 2 seconds</f:format.date>

Expected result:

13.12.1980 - 21:03:42
(depending on the current time, see http://www.php.net/manual/en/function.strtotime.php)

output date from unix timestamp:

<f:format.date format="d.m.Y - H:i:s">@{someTimestamp}</f:format.date>

Expected result:

13.12.1980 - 21:03:42
(depending on the current time. Don't forget the "@" in front of the timestamp see http://www.php.net/manual/en/function.strtotime.php)

Inline notation:

{f:format.date(date: dateObject)}

Expected result:

1980-12-13
(depending on the value of {dateObject})

Inline notation (2nd variant):

{dateObject -> f:format.date()}

Expected result:

1980-12-13
(depending on the value of {dateObject})

Inline notation, outputting date only, using current locale:

{dateObject -> f:format.date(localeFormatType: 'date', forceLocale: true)}

Expected result:

13.12.1980
(depending on the value of {dateObject} and the current locale)

Inline notation with specific locale used:

{dateObject -> f:format.date(forceLocale: 'de_DE')}

Expected result:

13.12.1980 11:15:42
(depending on the value of {dateObject})
f:format.htmlentities

Applies htmlentities() escaping to a value

Implementation:TYPO3\Fluid\ViewHelpers\Format\HtmlentitiesViewHelper
Arguments
  • value (string, optional): string to format
  • keepQuotes (boolean, optional): if TRUE, single and double quotes won’t be replaced (sets ENT_NOQUOTES flag)
  • encoding (string, optional)
  • doubleEncode (boolean, optional): If FALSE existing html entities won’t be encoded, the default is to convert everything.
f:format.htmlentitiesDecode

Applies html_entity_decode() to a value

Implementation:TYPO3\Fluid\ViewHelpers\Format\HtmlentitiesDecodeViewHelper
Arguments
  • value (string, optional): string to format
  • keepQuotes (boolean, optional): if TRUE, single and double quotes won’t be replaced (sets ENT_NOQUOTES flag)
  • encoding (string, optional)
f:format.htmlspecialchars

Applies htmlspecialchars() escaping to a value

Implementation:TYPO3\Fluid\ViewHelpers\Format\HtmlspecialcharsViewHelper
Arguments
  • value (string, optional): string to format
  • keepQuotes (boolean, optional): if TRUE, single and double quotes won’t be replaced (sets ENT_NOQUOTES flag)
  • encoding (string, optional)
  • doubleEncode (boolean, optional): If FALSE existing html entities won’t be encoded, the default is to convert everything.
f:format.identifier

This ViewHelper renders the identifier of a persisted object (if it has an identity). Usually the identifier is the UUID of the object, but it could be an array of the identity properties, too.

Implementation:TYPO3\Fluid\ViewHelpers\Format\IdentifierViewHelper
Arguments
  • value (object, optional): the object to render the identifier for, or NULL if VH children should be used
f:format.json

Wrapper for PHPs json_encode function.

Implementation:TYPO3\Fluid\ViewHelpers\Format\JsonViewHelper
Arguments
  • value (mixed, optional): The incoming data to convert, or NULL if VH children should be used
  • forceObject (boolean, optional): Outputs an JSON object rather than an array
Examples

encoding a view variable:

{someArray -> f:format.json()}

Expected result:

["array","values"]
// depending on the value of {someArray}

associative array:

{f:format.json(value: {foo: 'bar', bar: 'baz'})}

Expected result:

{"foo":"bar","bar":"baz"}

non-associative array with forced object:

{f:format.json(value: {0: 'bar', 1: 'baz'}, forceObject: true)}

Expected result:

{"0":"bar","1":"baz"}
f:format.nl2br

Wrapper for PHPs nl2br function.

Implementation:TYPO3\Fluid\ViewHelpers\Format\Nl2brViewHelper
Arguments
  • value (string, optional): string to format
f:format.number

Formats a number with custom precision, decimal point and grouped thousands.

Implementation:TYPO3\Fluid\ViewHelpers\Format\NumberViewHelper
Arguments
  • forceLocale (mixed, optional): Whether if, and what, Locale should be used. May be boolean, string or TYPO3FlowI18nLocale
  • decimals (integer, optional): The number of digits after the decimal point
  • decimalSeparator (string, optional): The decimal point character
  • thousandsSeparator (string, optional): The character for grouping the thousand digits
  • localeFormatLength (string, optional): Format length if locale set in $forceLocale. Must be one of TYPO3FlowI18nCldrReaderNumbersReader::FORMAT_LENGTH_*’s constants.
f:format.padding

Formats a string using PHPs str_pad function.

Implementation:TYPO3\Fluid\ViewHelpers\Format\PaddingViewHelper
Arguments
  • padLength (integer): Length of the resulting string. If the value of pad_length is negative or less than the length of the input string, no padding takes place.
  • padString (string, optional): The padding string
  • padType (string, optional): Append the padding at this site (Possible values: right,left,both. Default: right)
  • value (string, optional): string to format
f:format.printf

A view helper for formatting values with printf. Either supply an array for the arguments or a single value. See http://www.php.net/manual/en/function.sprintf.php

Implementation:TYPO3\Fluid\ViewHelpers\Format\PrintfViewHelper
Arguments
  • arguments (array): The arguments for vsprintf
  • value (string, optional): string to format
Examples

Scientific notation:

<f:format.printf arguments="{number: 362525200}">%.3e</f:format.printf>

Expected result:

3.625e+8

Argument swapping:

<f:format.printf arguments="{0: 3, 1: 'Kasper'}">%2$s is great, TYPO%1$d too. Yes, TYPO%1$d is great and so is %2$s!</f:format.printf>

Expected result:

Kasper is great, TYPO3 too. Yes, TYPO3 is great and so is Kasper!

Single argument:

<f:format.printf arguments="{1: 'TYPO3'}">We love %s</f:format.printf>

Expected result:

We love TYPO3

Inline notation:

{someText -> f:format.printf(arguments: {1: 'TYPO3'})}

Expected result:

We love TYPO3
f:format.raw

Outputs an argument/value without any escaping. Is normally used to output an ObjectAccessor which should not be escaped, but output as-is.

PAY SPECIAL ATTENTION TO SECURITY HERE (especially Cross Site Scripting), as the output is NOT SANITIZED!

Implementation:TYPO3\Fluid\ViewHelpers\Format\RawViewHelper
Arguments
  • value (mixed, optional): The value to output
Examples

Child nodes:

<f:format.raw>{string}</f:format.raw>

Expected result:

(Content of {string} without any conversion/escaping)

Value attribute:

<f:format.raw value="{string}" />

Expected result:

(Content of {string} without any conversion/escaping)

Inline notation:

{string -> f:format.raw()}

Expected result:

(Content of {string} without any conversion/escaping)
f:format.stripTags

Removes tags from the given string (applying PHPs strip_tags() function)

Implementation:TYPO3\Fluid\ViewHelpers\Format\StripTagsViewHelper
Arguments
  • value (string, optional): string to format
f:format.urlencode

Encodes the given string according to http://www.faqs.org/rfcs/rfc3986.html (applying PHPs rawurlencode() function)

Implementation:TYPO3\Fluid\ViewHelpers\Format\UrlencodeViewHelper
Arguments
  • value (string, optional): string to format
f:groupedFor

Grouped loop view helper. Loops through the specified values.

The groupBy argument also supports property paths.

Implementation:TYPO3\Fluid\ViewHelpers\GroupedForViewHelper
Arguments
  • each (array): The array or SplObjectStorage to iterated over
  • as (string): The name of the iteration variable
  • groupBy (string): Group by this property
  • groupKey (string, optional): The name of the variable to store the current group
Examples

Simple:

<f:groupedFor each="{0: {name: 'apple', color: 'green'}, 1: {name: 'cherry', color: 'red'}, 2: {name: 'banana', color: 'yellow'}, 3: {name: 'strawberry', color: 'red'}}" as="fruitsOfThisColor" groupBy="color">
  <f:for each="{fruitsOfThisColor}" as="fruit">
    {fruit.name}
  </f:for>
</f:groupedFor>

Expected result:

apple cherry strawberry banana

Two dimensional list:

<ul>
  <f:groupedFor each="{0: {name: 'apple', color: 'green'}, 1: {name: 'cherry', color: 'red'}, 2: {name: 'banana', color: 'yellow'}, 3: {name: 'strawberry', color: 'red'}}" as="fruitsOfThisColor" groupBy="color" groupKey="color">
    <li>
      {color} fruits:
      <ul>
        <f:for each="{fruitsOfThisColor}" as="fruit" key="label">
          <li>{label}: {fruit.name}</li>
        </f:for>
      </ul>
    </li>
  </f:groupedFor>
</ul>

Expected result:

<ul>
  <li>green fruits
    <ul>
      <li>0: apple</li>
    </ul>
  </li>
  <li>red fruits
    <ul>
      <li>1: cherry</li>
    </ul>
    <ul>
      <li>3: strawberry</li>
    </ul>
  </li>
  <li>yellow fruits
    <ul>
      <li>2: banana</li>
    </ul>
  </li>
</ul>
f:if

This view helper implements an if/else condition. Check TYPO3FluidCoreParserSyntaxTreeViewHelperNode::convertArgumentValue() to see how boolean arguments are evaluated

Conditions:

As a condition is a boolean value, you can just use a boolean argument. Alternatively, you can write a boolean expression there. Boolean expressions have the following form: XX Comparator YY Comparator is one of: ==, !=, <, <=, >, >= and % The % operator converts the result of the % operation to boolean.

XX and YY can be one of: - number - string - Object Accessor - Array - a ViewHelper

<f:if condition="{rank} > 100">
  Will be shown if rank is > 100
</f:if>
<f:if condition="{rank} % 2">
  Will be shown if rank % 2 != 0.
</f:if>
<f:if condition="{rank} == {k:bar()}">
  Checks if rank is equal to the result of the ViewHelper "k:bar"
</f:if>
<f:if condition="{foo.bar} == 'stringToCompare'">
  Will result true if {foo.bar}'s represented value equals 'stringToCompare'.
</f:if>
Implementation:TYPO3\Fluid\ViewHelpers\IfViewHelper
Arguments
  • then (mixed, optional): Value to be returned if the condition if met.
  • else (mixed, optional): Value to be returned if the condition if not met.
  • condition (boolean): View helper condition
Examples

Basic usage:

<f:if condition="somecondition">
  This is being shown in case the condition matches
</f:if>

Expected result:

Everything inside the <f:if> tag is being displayed if the condition evaluates to TRUE.

If / then / else:

<f:if condition="somecondition">
  <f:then>
    This is being shown in case the condition matches.
  </f:then>
  <f:else>
    This is being displayed in case the condition evaluates to FALSE.
  </f:else>
</f:if>

Expected result:

Everything inside the "then" tag is displayed if the condition evaluates to TRUE.
Otherwise, everything inside the "else"-tag is displayed.

inline notation:

{f:if(condition: someVariable, then: 'condition is met', else: 'condition is not met')}

Expected result:

The value of the "then" attribute is displayed if the variable evaluates to TRUE.
Otherwise, everything the value of the "else"-attribute is displayed.

inline notation with comparison:

{f:if(condition: '{workspace} == {userWorkspace}', then: 'this is a user workspace', else: 'no user workspace')}

Expected result:

If the condition is not just a single variable, the whole expression must be enclosed in quotes and variables need
to be enclosed in curly braces.
f:layout

With this tag, you can select a layout to be used for the current template.

Implementation:TYPO3\Fluid\ViewHelpers\LayoutViewHelper
Arguments
  • name (string, optional): Name of layout to use. If none given, “Default” is used.
f:render

A ViewHelper to render a section or a specified partial in a template.

Implementation:TYPO3\Fluid\ViewHelpers\RenderViewHelper
Arguments
  • section (string, optional): Name of section to render. If used in a layout, renders a section of the main content file. If used inside a standard template, renders a section of the same file.
  • partial (string, optional): Reference to a partial.
  • arguments (array, optional): Arguments to pass to the partial.
  • optional (boolean, optional): Set to TRUE, to ignore unknown sections, so the definition of a section inside a template can be optional for a layout
Examples

Rendering partials:

<f:render partial="SomePartial" arguments="{foo: someVariable}" />

Expected result:

the content of the partial "SomePartial". The content of the variable {someVariable} will be available in the partial as {foo}

Rendering sections:

<f:section name="someSection">This is a section. {foo}</f:section>
<f:render section="someSection" arguments="{foo: someVariable}" />

Expected result:

the content of the section "someSection". The content of the variable {someVariable} will be available in the partial as {foo}

Rendering recursive sections:

<f:section name="mySection">
 <ul>
   <f:for each="{myMenu}" as="menuItem">
     <li>
       {menuItem.text}
       <f:if condition="{menuItem.subItems}">
         <f:render section="mySection" arguments="{myMenu: menuItem.subItems}" />
       </f:if>
     </li>
   </f:for>
 </ul>
</f:section>
<f:render section="mySection" arguments="{myMenu: menu}" />

Expected result:

<ul>
  <li>menu1
    <ul>
      <li>menu1a</li>
      <li>menu1b</li>
    </ul>
  </li>
[...]
(depending on the value of {menu})

Passing all variables to a partial:

<f:render partial="somePartial" arguments="{_all}" />

Expected result:

the content of the partial "somePartial".
Using the reserved keyword "_all", all available variables will be passed along to the partial
f:renderChildren

Render the inner parts of a Widget. This ViewHelper can only be used in a template which belongs to a Widget Controller.

It renders everything inside the Widget ViewHelper, and you can pass additional arguments.

Implementation:TYPO3\Fluid\ViewHelpers\RenderChildrenViewHelper
Arguments
  • arguments (array, optional)
Examples

Basic usage:

<!-- in the widget template -->
Header
<f:renderChildren arguments="{foo: 'bar'}" />
Footer

<-- in the outer template, using the widget -->

<x:widget.someWidget>
  Foo: {foo}
</x:widget.someWidget>

Expected result:

Header
Foo: bar
Footer
f:section

A ViewHelper to declare sections in templates for later use with e.g. the RenderViewHelper.

Implementation:TYPO3\Fluid\ViewHelpers\SectionViewHelper
Arguments
  • name (string): Name of the section
Examples

Rendering sections:

<f:section name="someSection">This is a section. {foo}</f:section>
<f:render section="someSection" arguments="{foo: someVariable}" />

Expected result:

the content of the section "someSection". The content of the variable {someVariable} will be available in the partial as {foo}

Rendering recursive sections:

<f:section name="mySection">
 <ul>
   <f:for each="{myMenu}" as="menuItem">
     <li>
       {menuItem.text}
       <f:if condition="{menuItem.subItems}">
         <f:render section="mySection" arguments="{myMenu: menuItem.subItems}" />
       </f:if>
     </li>
   </f:for>
 </ul>
</f:section>
<f:render section="mySection" arguments="{myMenu: menu}" />

Expected result:

<ul>
  <li>menu1
    <ul>
      <li>menu1a</li>
      <li>menu1b</li>
    </ul>
  </li>
[...]
(depending on the value of {menu})
f:security.csrfToken

ViewHelper that outputs a CSRF token which is required for “unsafe” requests (e.g. POST, PUT, DELETE, …).

Note: You won’t need this ViewHelper if you use the Form ViewHelper, because that creates a hidden field with the CSRF token for unsafe requests automatically. This ViewHelper is mainly useful in conjunction with AJAX.

Implementation:TYPO3\Fluid\ViewHelpers\Security\CsrfTokenViewHelper
f:security.ifAccess

This view helper implements an ifAccess/else condition.

Implementation:TYPO3\Fluid\ViewHelpers\Security\IfAccessViewHelper
Arguments
  • then (mixed, optional): Value to be returned if the condition if met.
  • else (mixed, optional): Value to be returned if the condition if not met.
  • privilegeTarget (string): The Privilege target identifier
  • parameters (array, optional): optional privilege target parameters to be evaluated
f:security.ifAuthenticated

This view helper implements an ifAuthenticated/else condition.

Implementation:TYPO3\Fluid\ViewHelpers\Security\IfAuthenticatedViewHelper
Arguments
  • then (mixed, optional): Value to be returned if the condition if met.
  • else (mixed, optional): Value to be returned if the condition if not met.
f:security.ifHasRole

This view helper implements an ifHasRole/else condition.

Implementation:TYPO3\Fluid\ViewHelpers\Security\IfHasRoleViewHelper
Arguments
  • then (mixed, optional): Value to be returned if the condition if met.
  • else (mixed, optional): Value to be returned if the condition if not met.
  • role (string): The role or role identifier
  • packageKey (string, optional): PackageKey of the package defining the role
  • account (TYPO3FlowSecurityAccount, optional): If specified, this subject of this check is the given Account instead of the currently authenticated account
f:switch

Switch view helper which can be used to render content depending on a value or expression. Implements what a basic switch()-PHP-method does.

An optional default case can be specified which is rendered if none of the “f:case” conditions matches.

Implementation:TYPO3\Fluid\ViewHelpers\SwitchViewHelper
Arguments
  • expression (mixed)
Examples

Simple Switch statement:

<f:switch expression="{person.gender}">
  <f:case value="male">Mr.</f:case>
  <f:case value="female">Mrs.</f:case>
  <f:defaultCase>Mr. / Mrs.</f:defaultCase>
</f:switch>

Expected result:

"Mr.", "Mrs." or "Mr. / Mrs." (depending on the value of {person.gender})
f:then

“THEN” -> only has an effect inside of “IF”. See If-ViewHelper for documentation.

Implementation:TYPO3\Fluid\ViewHelpers\ThenViewHelper
f:translate

Returns translated message using source message or key ID.

Also replaces all placeholders with formatted versions of provided values.

Implementation:TYPO3\Fluid\ViewHelpers\TranslateViewHelper
Arguments
  • id (string, optional): Id to use for finding translation (trans-unit id in XLIFF)
  • value (string, optional): If $key is not specified or could not be resolved, this value is used. If this argument is not set, child nodes will be used to render the default
  • arguments (array, optional): Numerically indexed array of values to be inserted into placeholders
  • source (string, optional): Name of file with translations
  • package (string, optional): Target package key. If not set, the current package key will be used
  • quantity (mixed, optional): A number to find plural form for (float or int), NULL to not use plural forms
  • locale (string, optional): An identifier of locale to use (NULL for use the default locale)
Examples

Translation by id:

<f:translate id="user.unregistered">Unregistered User</f:translate>

Expected result:

translation of label with the id "user.unregistered" and a fallback to "Unregistered User"

Inline notation:

{f:translate(id: 'some.label.id', value: 'fallback result')}

Expected result:

translation of label with the id "some.label.id" and a fallback to "fallback result"

Custom source and locale:

<f:translate id="some.label.id" source="LabelsCatalog" locale="de_DE"/>

Expected result:

translation from custom source "SomeLabelsCatalog" for locale "de_DE"

Custom source from other package:

<f:translate id="some.label.id" source="LabelsCatalog" package="OtherPackage"/>

Expected result:

translation from custom source "LabelsCatalog" in "OtherPackage"

Arguments:

<f:translate arguments="{0: 'foo', 1: '99.9'}"><![CDATA[Untranslated {0} and {1,number}]]></f:translate>

Expected result:

translation of the label "Untranslated foo and 99.9"

Translation by label:

<f:translate>Untranslated label</f:translate>

Expected result:

translation of the label "Untranslated label"
f:uri.action

A view helper for creating URIs to actions.

Implementation:TYPO3\Fluid\ViewHelpers\Uri\ActionViewHelper
Arguments
  • action (string): Target action
  • arguments (array, optional): Arguments
  • controller (string, optional): Target controller. If NULL current controllerName is used
  • package (string, optional): Target package. if NULL current package is used
  • subpackage (string, optional): Target subpackage. if NULL current subpackage is used
  • section (string, optional): The anchor to be added to the URI
  • format (string, optional): The requested format, e.g. “.html
  • additionalParams (array, optional): additional query parameters that won’t be prefixed like $arguments (overrule $arguments)
  • absolute (boolean, optional): If set, an absolute URI is rendered
  • addQueryString (boolean, optional): If set, the current query parameters will be kept in the URI
  • argumentsToBeExcludedFromQueryString (array, optional): arguments to be removed from the URI. Only active if $addQueryString = TRUE
  • useParentRequest (boolean, optional): If set, the parent Request will be used instead of the current one
Examples

Defaults:

<f:uri.action>some link</f:uri.action>

Expected result:

currentpackage/currentcontroller
(depending on routing setup and current package/controller/action)

Additional arguments:

<f:uri.action action="myAction" controller="MyController" package="YourCompanyName.MyPackage" subpackage="YourCompanyName.MySubpackage" arguments="{key1: 'value1', key2: 'value2'}">some link</f:uri.action>

Expected result:

mypackage/mycontroller/mysubpackage/myaction?key1=value1&amp;key2=value2
(depending on routing setup)
f:uri.email

Email uri view helper. Currently the specified email is simply prepended by “mailto:” but we might add spam protection.

Implementation:TYPO3\Fluid\ViewHelpers\Uri\EmailViewHelper
Arguments
  • email (string): The email address to be turned into a mailto uri.
Examples

basic email uri:

<f:uri.email email="foo@bar.tld" />

Expected result:

mailto:foo@bar.tld
f:uri.external

A view helper for creating URIs to external targets. Currently the specified URI is simply passed through.

Implementation:TYPO3\Fluid\ViewHelpers\Uri\ExternalViewHelper
Arguments
  • uri (string): target URI
  • defaultScheme (string, optional): scheme the href attribute will be prefixed with if specified $uri does not contain a scheme already
Examples

custom default scheme:

<f:uri.external uri="typo3.org" defaultScheme="ftp" />

Expected result:

ftp://typo3.org
f:uri.resource

A view helper for creating URIs to resources.

Implementation:TYPO3\Fluid\ViewHelpers\Uri\ResourceViewHelper
Arguments
  • path (string, optional): The location of the resource, can be either a path relative to the Public resource directory of the package or a resource://… URI
  • package (string, optional): Target package key. If not set, the current package key will be used
  • resource (TYPO3FlowResourceResource, optional): If specified, this resource object is used instead of the path and package information
  • localize (boolean, optional): Whether resource localization should be attempted or not
Examples

Defaults:

<link href="{f:uri.resource(path: 'CSS/Stylesheet.css')}" rel="stylesheet" />

Expected result:

<link href="http://yourdomain.tld/_Resources/Static/YourPackage/CSS/Stylesheet.css" rel="stylesheet" />
(depending on current package)

Other package resource:

{f:uri.resource(path: 'gfx/SomeImage.png', package: 'DifferentPackage')}

Expected result:

http://yourdomain.tld/_Resources/Static/DifferentPackage/gfx/SomeImage.png
(depending on domain)

Resource URI:

{f:uri.resource(path: 'resource://DifferentPackage/Public/gfx/SomeImage.png')}

Expected result:

http://yourdomain.tld/_Resources/Static/DifferentPackage/gfx/SomeImage.png
(depending on domain)

Resource object:

<img src="{f:uri.resource(resource: myImage.resource)}" />

Expected result:

<img src="http://yourdomain.tld/_Resources/Persistent/69e73da3ce0ad08c717b7b9f1c759182d6650944.jpg" />
(depending on your resource object)
f:validation.ifHasErrors

This view helper allows to check whether validation errors adhere to the current request.

Implementation:TYPO3\Fluid\ViewHelpers\Validation\IfHasErrorsViewHelper
Arguments
  • then (mixed, optional): Value to be returned if the condition if met.
  • else (mixed, optional): Value to be returned if the condition if not met.
  • for (string, optional): The argument or property name or path to check for error(s)
f:validation.results

Validation results view helper

Implementation:TYPO3\Fluid\ViewHelpers\Validation\ResultsViewHelper
Arguments
  • for (string, optional): The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.
  • as (string, optional): The name of the variable to store the current error
Examples

Output error messages as a list:

<f:validation.results>
  <f:if condition="{validationResults.flattenedErrors}">
    <ul class="errors">
      <f:for each="{validationResults.flattenedErrors}" as="errors" key="propertyPath">
        <li>{propertyPath}
          <ul>
          <f:for each="{errors}" as="error">
            <li>{error.code}: {error}</li>
          </f:for>
          </ul>
        </li>
      </f:for>
    </ul>
  </f:if>
</f:validation.results>

Expected result:

<ul class="errors">
  <li>1234567890: Validation errors for argument "newBlog"</li>
</ul>

Output error messages for a single property:

<f:validation.results for="someProperty">
  <f:if condition="{validationResults.flattenedErrors}">
    <ul class="errors">
      <f:for each="{validationResults.errors}" as="error">
        <li>{error.code}: {error}</li>
      </f:for>
    </ul>
  </f:if>
</f:validation.results>

Expected result:

<ul class="errors">
  <li>1234567890: Some error message</li>
</ul>
f:widget.autocomplete

Usage: <f:input id=”name” … /> <f:widget.autocomplete for=”name” objects=”{posts}” searchProperty=”author”>

Make sure to include jQuery and jQuery UI in the HTML, like that:
<script type=”text/javascript” src=”http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js”></script> <script type=”text/javascript” src=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js”></script> <link rel=”stylesheet” href=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.3/themes/base/jquery-ui.css” type=”text/css” media=”all” /> <link rel=”stylesheet” href=”http://static.jquery.com/ui/css/demo-docs-theme/ui.theme.css” type=”text/css” media=”all” />
Implementation:TYPO3\Fluid\ViewHelpers\Widget\AutocompleteViewHelper
Arguments
  • objects (TYPO3FlowPersistenceQueryResultInterface)
  • for (string)
  • searchProperty (string)
  • configuration (array, optional)
  • widgetId (string, optional): Unique identifier of the widget instance
f:widget.paginate

This ViewHelper renders a Pagination of objects.

Implementation:TYPO3\Fluid\ViewHelpers\Widget\PaginateViewHelper
Arguments
  • objects (TYPO3FlowPersistenceQueryResultInterface)
  • as (string)
  • configuration (array, optional)
  • widgetId (string, optional): Unique identifier of the widget instance
f:widget.uri

widget.uri ViewHelper This ViewHelper can be used inside widget templates in order to render URIs pointing to widget actions

Implementation:TYPO3\Fluid\ViewHelpers\Widget\UriViewHelper
Arguments
  • action (string, optional): Target action
  • arguments (array, optional): Arguments
  • section (string, optional): The anchor to be added to the URI
  • format (string, optional): The requested format, e.g. “.html
  • ajax (boolean, optional): TRUE if the URI should be to an AJAX widget, FALSE otherwise.
  • includeWidgetContext (boolean, optional): TRUE if the URI should contain the serialized widget context (only useful for stateless AJAX widgets)

Form ViewHelper Reference

This reference was automatically generated from code on 2016-06-21

typo3.form:form

Custom form ViewHelper that renders the form state instead of referrer fields

Implementation:TYPO3\Form\ViewHelpers\FormViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • action (string, optional): target action
  • arguments (array, optional): additional arguments
  • controller (string, optional): name of target controller
  • package (string, optional): name of target package
  • subpackage (string, optional): name of target subpackage
  • object (mixed, optional): object to use for the form. Use in conjunction with the “property” attribute on the sub tags
  • section (string, optional): The anchor to be added to the action URI (only active if $actionUri is not set)
  • format (string, optional): The requested format (e.g. “.html”) of the target page (only active if $actionUri is not set)
  • additionalParams (array, optional): additional action URI query parameters that won’t be prefixed like $arguments (overrule $arguments) (only active if $actionUri is not set)
  • absolute (boolean, optional): If set, an absolute action URI is rendered (only active if $actionUri is not set)
  • addQueryString (boolean, optional): If set, the current query parameters will be kept in the action URI (only active if $actionUri is not set)
  • argumentsToBeExcludedFromQueryString (array, optional): arguments to be removed from the action URI. Only active if $addQueryString = TRUE and $actionUri is not set
  • fieldNamePrefix (string, optional): Prefix that will be added to all field names within this form
  • actionUri (string, optional): can be used to overwrite the “action” attribute of the form tag
  • objectName (string, optional): name of the object that is bound to this form. If this argument is not specified, the name attribute of this form is used to determine the FormObjectName
  • useParentRequest (boolean, optional): If set, the parent Request will be used instead ob the current one
  • enctype (string, optional): MIME type with which the form is submitted
  • method (string, optional): Transfer type (GET or POST)
  • name (string, optional): Name of form
  • onreset (string, optional): JavaScript: On reset of the form
  • onsubmit (string, optional): JavaScript: On submit of the form
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
typo3.form:form.datePicker

Display a jQuery date picker.

Note: Requires jQuery UI to be included on the page.

Implementation:TYPO3\Form\ViewHelpers\Form\DatePickerViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • dateFormat (string, optional)
  • enableDatePicker (boolean, optional)
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • size (int, optional): The size of the input field
  • placeholder (string, optional): Specifies a short hint that describes the expected value of an input element
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • initialDate (string, optional): Initial date (@see http://www.php.net/manual/en/datetime.formats.php for supported formats)
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
typo3.form:form.formElementRootlinePath

Form Element Rootline Path

Implementation:TYPO3\Form\ViewHelpers\Form\FormElementRootlinePathViewHelper
Arguments
  • renderable (TYPO3FormCoreModelRenderableRenderableInterface)
typo3.form:form.timePicker

Displays two select-boxes for hour and minute selection.

Implementation:TYPO3\Form\ViewHelpers\Form\TimePickerViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • size (int, optional): The size of the select field
  • placeholder (string, optional): Specifies a short hint that describes the expected value of an input element
  • disabled (string, optional): Specifies that the select element should be disabled when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • initialDate (string, optional): Initial time (@see http://www.php.net/manual/en/datetime.formats.php for supported formats)
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
typo3.form:form.uploadedImage

This ViewHelper makes the specified Image object available for its childNodes. In case the form is redisplayed because of validation errors, a previously uploaded image will be correctly used.

Implementation:TYPO3\Form\ViewHelpers\Form\UploadedImageViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • as (string, optional)
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
Examples

Example:

<f:form.upload property="image" />
<c:form.uploadedImage property="image" as="theImage">
  <a href="{f:uri.resource(resource: theImage.resource)}">Link to image resource</a>
</c:form.uploadedImage>

Expected result:

<a href="...">Link to image resource</a>
typo3.form:form.uploadedResource

This ViewHelper makes the specified Resource object available for its childNodes. If no resource object wsa found at the specified position, the child nodes are not rendered.

In case the form is redisplayed because of validation errors, a previously uploaded resource will be correctly used.

Implementation:TYPO3\Form\ViewHelpers\Form\UploadedResourceViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • as (string, optional)
  • name (string, optional): Name of input tag
  • value (mixed, optional): Value of input tag
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
Examples

Example:

<f:form.upload property="file" />
<c:form.uploadedResource property="file" as="theResource">
  <a href="{f:uri.resource(resource: theResource)}">Link to resource</a>
</c:form.uploadedResource>

Expected result:

<a href="...">Link to resource</a>
typo3.form:render

Main Entry Point to render a Form into a Fluid Template

<pre> {namespace form=TYPO3FormViewHelpers} <form:render factoryClass=”NameOfYourCustomFactoryClass” /> </pre>

The factory class must implement {@link TYPO3FormFactoryFormFactoryInterface}.

Implementation:TYPO3\Form\ViewHelpers\RenderViewHelper
Arguments
  • persistenceIdentifier (string, optional): the persistence identifier for the form.
  • factoryClass (string, optional): The fully qualified class name of the factory (which has to implement TYPO3FormFactoryFormFactoryInterface)
  • presetName (string, optional): name of the preset to use
  • overrideConfiguration (array, optional): factory specific configuration
typo3.form:renderHead

Output the configured stylesheets and JavaScript include tags for a given preset

Implementation:TYPO3\Form\ViewHelpers\RenderHeadViewHelper
Arguments
  • presetName (string, optional): name of the preset to use
typo3.form:renderRenderable

Render a renderable

Implementation:TYPO3\Form\ViewHelpers\RenderRenderableViewHelper
Arguments
  • renderable (TYPO3FormCoreModelRenderableRenderableInterface)
typo3.form:renderValues

Renders the values of a form

Implementation:TYPO3\Form\ViewHelpers\RenderValuesViewHelper
Arguments
  • renderable (TYPO3FormCoreModelRenderableRootRenderableInterface)
  • as (string, optional)
typo3.form:translateElementProperty

ViewHelper to translate the property of a given form element based on its rendering options

Implementation:TYPO3\Form\ViewHelpers\TranslateElementPropertyViewHelper
Arguments
  • property (string)
  • element (TYPO3FormCoreModelFormElementInterface, optional)

Media ViewHelper Reference

This reference was automatically generated from code on 2016-06-07

typo3.media:fileTypeIcon

Renders an <img> HTML tag for a filetype icon for a given TYPO3.Media’s asset instance

Implementation:TYPO3\Media\ViewHelpers\FileTypeIconViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • file (TYPO3MediaDomainModelAssetInterface)
  • width (integer|null, optional)
  • height (integer|null, optional)
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Rendering an asset filetype icon:

<typo3.media:fileTypeIcon asset="{assetObject}" alt="a filetype icon" height="16" />

Expected result:

(depending on the asset, no scaling applied)
<img src="_Resources/Static/Packages/TYPO3/Media/Icons/16px/jpg.png" height="16" alt="a filetype icon" />
typo3.media:form.checkbox

View Helper which creates a simple checkbox (<input type=”checkbox”>).

Implementation:TYPO3\Media\ViewHelpers\Form\CheckboxViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • checked (boolean, optional): Specifies that the input element should be preselected
  • multiple (boolean, optional): Specifies whether this checkbox belongs to a multivalue (is part of a checkbox group)
  • name (string, optional): Name of input tag
  • value (string): Value of input tag. Required for checkboxes
  • property (string, optional): Name of Object Property. If used in conjunction with <f:form object=”…”>, “name” and “value” properties will be ignored.
  • disabled (string, optional): Specifies that the input element should be disabled when the page loads
  • errorClass (string, optional): CSS class to set if there are errors for this view helper
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
Examples

Example:

<typo3.media:form.checkbox name="myCheckBox" value="someValue" />

Expected result:

<input type="checkbox" name="myCheckBox" value="someValue" />

Preselect:

<typo3.media:form.checkbox name="myCheckBox" value="someValue" checked="{object.value} == 5" />

Expected result:

<input type="checkbox" name="myCheckBox" value="someValue" checked="checked" />
(depending on $object)

Bind to object property:

<typo3.media:form.checkbox property="interests" value="TYPO3" />

Expected result:

<input type="checkbox" name="user[interests][]" value="TYPO3" checked="checked" />
(depending on property "interests")
typo3.media:format.relativeDate

Renders a DateTime formatted relative to the current date

Implementation:TYPO3\Media\ViewHelpers\Format\RelativeDateViewHelper
Arguments
  • date (DateTime, optional)
typo3.media:image

Renders an <img> HTML tag from a given TYPO3.Media’s image instance

Implementation:TYPO3\Media\ViewHelpers\ImageViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • image (TYPO3MediaDomainModelImageInterface, optional): The image to be rendered as an image
  • width (integer, optional): Desired width of the image
  • maximumWidth (integer, optional): Desired maximum width of the image
  • height (integer, optional): Desired height of the image
  • maximumHeight (integer, optional): Desired maximum height of the image
  • allowCropping (boolean, optional): Whether the image should be cropped if the given sizes would hurt the aspect ratio
  • allowUpScaling (boolean, optional): Whether the resulting image size might exceed the size of the original image
  • async (boolean, optional): Return asynchronous image URI in case the requested image does not exist already
  • preset (string, optional): Preset used to determine image configuration
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
  • alt (string): Specifies an alternate text for an image
  • ismap (string, optional): Specifies an image as a server-side image-map. Rarely used. Look at usemap instead
  • usemap (string, optional): Specifies an image as a client-side image-map
  • asset (TYPO3MediaDomainModelAssetInterface, optional): The asset to be rendered - DEPRECATED, use the “image” argument instead
Examples

Rendering an image as-is:

<typo3.media:image image="{imageObject}" alt="a sample image without scaling" />

Expected result:

(depending on the image, no scaling applied)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="120" height="180" alt="a sample image without scaling" />

Rendering an image with scaling at a given width only:

<typo3.media:image image="{imageObject}" maximumWidth="80" alt="sample" />

Expected result:

(depending on the image; scaled down to a maximum width of 80 pixels, keeping the aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="80" height="120" alt="sample" />

Rendering an image with scaling at given width and height, keeping aspect ratio:

<typo3.media:image image="{imageObject}" maximumWidth="80" maximumHeight="80" alt="sample" />

Expected result:

(depending on the image; scaled down to a maximum width and height of 80 pixels, keeping the aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="53" height="80" alt="sample" />

Rendering an image with crop-scaling at given width and height:

<typo3.media:image image="{imageObject}" maximumWidth="80" maximumHeight="80" allowCropping="true" alt="sample" />

Expected result:

(depending on the image; scaled down to a width and height of 80 pixels, possibly changing aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="80" height="80" alt="sample" />

Rendering an image with allowed up-scaling at given width and height:

<typo3.media:image image="{imageObject}" maximumWidth="5000" allowUpScaling="true" alt="sample" />

Expected result:

(depending on the image; scaled up or down to a width 5000 pixels, keeping aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="80" height="80" alt="sample" />
typo3.media:thumbnail

Renders an <img> HTML tag from a given TYPO3.Media’s asset instance

Implementation:TYPO3\Media\ViewHelpers\ThumbnailViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • asset (TYPO3MediaDomainModelAssetInterface, optional): The asset to be rendered as a thumbnail
  • width (integer, optional): Desired width of the thumbnail
  • maximumWidth (integer, optional): Desired maximum width of the thumbnail
  • height (integer, optional): Desired height of the thumbnail
  • maximumHeight (integer, optional): Desired maximum height of the thumbnail
  • allowCropping (boolean, optional): Whether the thumbnail should be cropped if the given sizes would hurt the aspect ratio
  • allowUpScaling (boolean, optional): Whether the resulting thumbnail size might exceed the size of the original asset
  • async (boolean, optional): Return asynchronous image URI in case the requested image does not exist already
  • preset (string, optional): Preset used to determine image configuration
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
  • alt (string): Specifies an alternate text for an asset
Examples

Rendering an asset thumbnail:

<typo3.media:thumbnail asset="{assetObject}" alt="a sample asset without scaling" />

Expected result:

(depending on the asset, no scaling applied)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="120" height="180" alt="a sample asset without scaling" />

Rendering an asset thumbnail with scaling at a given width only:

<typo3.media:thumbnail asset="{assetObject}" maximumWidth="80" alt="sample" />

Expected result:

(depending on the asset; scaled down to a maximum width of 80 pixels, keeping the aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="80" height="120" alt="sample" />

Rendering an asset thumbnail with scaling at given width and height, keeping aspect ratio:

<typo3.media:thumbnail asset="{assetObject}" maximumWidth="80" maximumHeight="80" alt="sample" />

Expected result:

(depending on the asset; scaled down to a maximum width and height of 80 pixels, keeping the aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="53" height="80" alt="sample" />

Rendering an asset thumbnail with crop-scaling at given width and height:

<typo3.media:thumbnail asset="{assetObject}" maximumWidth="80" maximumHeight="80" allowCropping="true" alt="sample" />

Expected result:

(depending on the asset; scaled down to a width and height of 80 pixels, possibly changing aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="80" height="80" alt="sample" />

Rendering an asset thumbnail with allowed up-scaling at given width and height:

<typo3.media:thumbnail asset="{assetObject}" maximumWidth="5000" allowUpScaling="true" alt="sample" />

Expected result:

(depending on the asset; scaled up or down to a width 5000 pixels, keeping aspect ratio)
<img src="_Resources/Persistent/b29[...]95d.jpeg" width="80" height="80" alt="sample" />
typo3.media:uri.image

Renders the src path of a thumbnail image of a given TYPO3.Media image instance

Implementation:TYPO3\Media\ViewHelpers\Uri\ImageViewHelper
Arguments
  • image (TYPO3MediaDomainModelImageInterface, optional)
  • width (integer, optional): Desired width of the image
  • maximumWidth (integer, optional): Desired maximum width of the image
  • height (integer, optional): Desired height of the image
  • maximumHeight (integer, optional): Desired maximum height of the image
  • allowCropping (boolean, optional): Whether the image should be cropped if the given sizes would hurt the aspect ratio
  • allowUpScaling (boolean, optional): Whether the resulting image size might exceed the size of the original image
  • async (boolean, optional): Return asynchronous image URI in case the requested image does not exist already
  • preset (string, optional): Preset used to determine image configuration
  • asset (TYPO3MediaDomainModelAssetInterface, optional): The image to be rendered - DEPRECATED, use the “image” argument instead
Examples

Rendering an image path as-is:

{typo3.media:uri.image(image: imageObject)}

Expected result:

(depending on the image)
_Resources/Persistent/b29[...]95d.jpeg

Rendering an image path with scaling at a given width only:

{typo3.media:uri.image(image: imageObject, maximumWidth: 80)}

Expected result:

(depending on the image; has scaled keeping the aspect ratio)
_Resources/Persistent/b29[...]95d.jpeg
typo3.media:uri.thumbnail

Renders the src path of a thumbnail image of a given TYPO3.Media asset instance

Implementation:TYPO3\Media\ViewHelpers\Uri\ThumbnailViewHelper
Arguments
  • asset (TYPO3MediaDomainModelAssetInterface, optional)
  • width (integer, optional): Desired width of the thumbnail
  • maximumWidth (integer, optional): Desired maximum width of the thumbnail
  • height (integer, optional): Desired height of the thumbnail
  • maximumHeight (integer, optional): Desired maximum height of the thumbnail
  • allowCropping (boolean, optional): Whether the thumbnail should be cropped if the given sizes would hurt the aspect ratio
  • allowUpScaling (boolean, optional): Whether the resulting thumbnail size might exceed the size of the original asset
  • async (boolean, optional): Return asynchronous image URI in case the requested image does not exist already
  • preset (string, optional): Preset used to determine image configuration
Examples

Rendering an asset thumbnail path as-is:

{typo3.media:uri.thumbnail(asset: assetObject)}

Expected result:

(depending on the asset)
_Resources/Persistent/b29[...]95d.jpeg

Rendering an asset thumbnail path with scaling at a given width only:

{typo3.media:uri.thumbnail(asset: assetObject, maximumWidth: 80)}

Expected result:

(depending on the asset; has scaled keeping the aspect ratio)
_Resources/Persistent/b29[...]95d.jpeg

Neos ViewHelper Reference

This reference was automatically generated from code on 2016-06-07

neos:backend.authenticationProviderLabel

Renders a label for the given authentication provider identifier

Implementation:TYPO3\Neos\ViewHelpers\Backend\AuthenticationProviderLabelViewHelper
Arguments
  • identifier (string)
neos:backend.changeStats

Displays a text-based “bar graph” giving an indication of the amount and type of changes done to something. Created for use in workspace management.

Implementation:TYPO3\Neos\ViewHelpers\Backend\ChangeStatsViewHelper
Arguments
  • changeCounts (array): Expected keys: new, changed, removed
neos:backend.colorOfString

Generates a color code for a given string

Implementation:TYPO3\Neos\ViewHelpers\Backend\ColorOfStringViewHelper
Arguments
  • string (string, optional)
  • minimalBrightness (integer, optional)
neos:backend.configurationCacheVersion

ViewHelper for rendering the current version identifier for the configuration cache.

Implementation:TYPO3\Neos\ViewHelpers\Backend\ConfigurationCacheVersionViewHelper
neos:backend.configurationTree

Render HTML markup for the full configuration tree in the Neos Administration -> Configuration Module.

For performance reasons, this is done inside a ViewHelper instead of Fluid itself.

Implementation:TYPO3\Neos\ViewHelpers\Backend\ConfigurationTreeViewHelper
Arguments
  • configuration (array)
neos:backend.container

ViewHelper for the backend ‘container’. Renders the required HTML to integrate the Neos backend into a website.

Implementation:TYPO3\Neos\ViewHelpers\Backend\ContainerViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface)
neos:backend.cssBuiltVersion

Returns a shortened md5 of the built CSS file

Implementation:TYPO3\Neos\ViewHelpers\Backend\CssBuiltVersionViewHelper
neos:backend.documentBreadcrumbPath

Render a bread crumb path by using the labels of documents leading to the given node path

Implementation:TYPO3\Neos\ViewHelpers\Backend\DocumentBreadcrumbPathViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface): A node
neos:backend.interfaceLanguage

ViewHelper for rendering the current backend users interface language.

Implementation:TYPO3\Neos\ViewHelpers\Backend\InterfaceLanguageViewHelper
neos:backend.javascriptBuiltVersion

Returns a shortened md5 of the built JavaScript file

Implementation:TYPO3\Neos\ViewHelpers\Backend\JavascriptBuiltVersionViewHelper
neos:backend.javascriptConfiguration

ViewHelper for the backend JavaScript configuration. Renders the required JS snippet to configure the Neos backend.

Implementation:TYPO3\Neos\ViewHelpers\Backend\JavascriptConfigurationViewHelper
neos:backend.shouldLoadMinifiedJavascript

Returns TRUE if the minified Neos JavaScript sources should be loaded, FALSE otherwise.

Implementation:TYPO3\Neos\ViewHelpers\Backend\ShouldLoadMinifiedJavascriptViewHelper
neos:backend.translate

Returns translated message using source message or key ID. uses the selected backend language * Also replaces all placeholders with formatted versions of provided values.

Implementation:TYPO3\Neos\ViewHelpers\Backend\TranslateViewHelper
Arguments
  • id (string, optional): Id to use for finding translation (trans-unit id in XLIFF)
  • value (string, optional): If $key is not specified or could not be resolved, this value is used. If this argument is not set, child nodes will be used to render the default
  • arguments (array, optional): Numerically indexed array of values to be inserted into placeholders
  • source (string, optional): Name of file with translations
  • package (string, optional): Target package key. If not set, the current package key will be used
  • quantity (mixed, optional): A number to find plural form for (float or int), NULL to not use plural forms
  • languageIdentifier (string, optional): An identifier of a language to use (NULL for using the default language)
Examples

Translation by id:

<neos:backend.translate id="user.unregistered">Unregistered User</neos:backend.translate>

Expected result:

translation of label with the id "user.unregistered" and a fallback to "Unregistered User"

Inline notation:

{neos:backend.translate(id: 'some.label.id', value: 'fallback result')}

Expected result:

translation of label with the id "some.label.id" and a fallback to "fallback result"

Custom source and locale:

<neos:backend.translate id="some.label.id" source="SomeLabelsCatalog" locale="de_DE"/>

Expected result:

translation from custom source "SomeLabelsCatalog" for locale "de_DE"

Custom source from other package:

<neos:backend.translate id="some.label.id" source="LabelsCatalog" package="OtherPackage"/>

Expected result:

translation from custom source "LabelsCatalog" in "OtherPackage"

Arguments:

<neos:backend.translate arguments="{0: 'foo', 1: '99.9'}"><![CDATA[Untranslated {0} and {1,number}]]></neos:backend.translate>

Expected result:

translation of the label "Untranslated foo and 99.9"

Translation by label:

<neos:backend.translate>Untranslated label</neos:backend.translate>

Expected result:

translation of the label "Untranslated label"
neos:backend.userInitials

Render user initials for a given username

This ViewHelper is WORK IN PROGRESS and NOT STABLE YET

Implementation:TYPO3\Neos\ViewHelpers\Backend\UserInitialsViewHelper
Arguments
  • format (string, optional): Supported are “fullFirstName” and “initials
neos:backend.xliffCacheVersion

ViewHelper for rendering the current version identifier for the xliff cache.

Implementation:TYPO3\Neos\ViewHelpers\Backend\XliffCacheVersionViewHelper
neos:contentElement.editable

Renders a wrapper around the inner contents of the tag to enable frontend editing.

The wrapper contains the property name which should be made editable, and is by default a “div” tag. The tag to use can be given as tag argument to the ViewHelper.

In live workspace this just renders a tag with the specified $tag-name containing the value of the given $property. For logged in users with access to the Backend this also adds required attributes for the RTE to work.

Note: when passing a node you have to make sure a metadata wrapper is used around this that matches the given node (see contentElement.wrap - i.e. the WrapViewHelper).

Implementation:TYPO3\Neos\ViewHelpers\ContentElement\EditableViewHelper
Arguments
  • additionalAttributes (array, optional): Additional tag attributes. They will be added directly to the resulting HTML tag.
  • data (array, optional): Additional data-* attributes. They will each be added with a “data-” prefix.
  • property (string): Name of the property to render. Note: If this tag has child nodes, they overrule this argument!
  • tag (string, optional): The name of the tag that should be wrapped around the property. By default this is a <div>
  • node (TYPO3TYPO3CRDomainModelNodeInterface, optional): The node of the content element. Optional, will be resolved from the TypoScript context by default.
  • class (string, optional): CSS class(es) for this element
  • dir (string, optional): Text direction for this HTML element. Allowed strings: “ltr” (left to right), “rtl” (right to left)
  • id (string, optional): Unique (in this file) identifier for this HTML element.
  • lang (string, optional): Language for this element. Use short names specified in RFC 1766
  • style (string, optional): Individual CSS styles for this element
  • title (string, optional): Tooltip text of element
  • accesskey (string, optional): Keyboard shortcut to access this element
  • tabindex (integer, optional): Specifies the tab order of this element
  • onclick (string, optional): JavaScript evaluated for the onclick event
neos:contentElement.wrap

A view helper for manually wrapping content editables.

Note that using this view helper is usually not necessary as Neos will automatically wrap editables of content elements.

By explicitly wrapping template parts with node meta data that is required for the backend to show properties in the inspector, this ViewHelper enables usage of the contentElement.editable ViewHelper outside of content element templates. This is useful if you want to make properties of a custom document node inline-editable.

Implementation:TYPO3\Neos\ViewHelpers\ContentElement\WrapViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface, optional): The node of the content element. Optional, will be resolved from the TypoScript context by default.
neos:getType

View helper to check if a given value is an array.

Implementation:TYPO3\Neos\ViewHelpers\GetTypeViewHelper
Arguments
  • value (mixed, optional): The value to determine the type of
Examples

Basic usage:

{neos:getType(value: 'foo')}

Expected result:

string

Use with shorthand syntax:

{myValue -> neos:getType()}

Expected result:

string
(if myValue is a string)
neos:includeJavaScript

A View Helper to include JavaScript files inside Resources/Public/JavaScript of the package.

Implementation:TYPO3\Neos\ViewHelpers\IncludeJavaScriptViewHelper
Arguments
  • include (string): Regular expression of files to include
  • exclude (string, optional): Regular expression of files to exclude
  • package (string, optional): The package key of the resources to include or current controller package if NULL
  • subpackage (string, optional): The subpackage key of the resources to include or current controller subpackage if NULL
  • directory (string, optional): The directory inside the current subpackage. By default, the “JavaScript” directory will be used.
neos:node.closestDocument

ViewHelper to find the closest document node to a given node

Implementation:TYPO3\Neos\ViewHelpers\Node\ClosestDocumentViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface)
neos:rendering.inBackend

ViewHelper to find out if Neos is rendering the backend.

Implementation:TYPO3\Neos\ViewHelpers\Rendering\InBackendViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface, optional)
Examples

Basic usage:

<f:if condition="{neos:rendering.inBackend()}">
  <f:then>
    Shown in the backend.
  </f:then>
  <f:else>
    Shown when not in backend.
  </f:else>
</f:if>

Expected result:

Shown in the backend.
neos:rendering.inEditMode

ViewHelper to find out if Neos is rendering an edit mode.

Implementation:TYPO3\Neos\ViewHelpers\Rendering\InEditModeViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface, optional): Optional Node to use context from
  • mode (string, optional): Optional rendering mode name to check if this specific mode is active
Examples

Basic usage:

<f:if condition="{neos:rendering.inEditMode()}">
  <f:then>
    Shown for editing.
  </f:then>
  <f:else>
    Shown elsewhere (preview mode or not in backend).
  </f:else>
</f:if>

Expected result:

Shown for editing.

Advanced usage:

<f:if condition="{neos:rendering.inEditMode(mode: 'rawContent')}">
  <f:then>
    Shown just for rawContent editing mode.
  </f:then>
  <f:else>
    Shown in all other cases.
  </f:else>
</f:if>

Expected result:

Shown in all other cases.
neos:rendering.inPreviewMode

ViewHelper to find out if Neos is rendering a preview mode.

Implementation:TYPO3\Neos\ViewHelpers\Rendering\InPreviewModeViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface, optional): Optional Node to use context from
  • mode (string, optional): Optional rendering mode name to check if this specific mode is active
Examples

Basic usage:

<f:if condition="{neos:rendering.inPreviewMode()}">
  <f:then>
    Shown in preview.
  </f:then>
  <f:else>
    Shown elsewhere (edit mode or not in backend).
  </f:else>
</f:if>

Expected result:

Shown in preview.

Advanced usage:

<f:if condition="{neos:rendering.inPreviewMode(mode: 'print')}">
  <f:then>
    Shown just for print preview mode.
  </f:then>
  <f:else>
    Shown in all other cases.
  </f:else>
</f:if>

Expected result:

Shown in all other cases.
neos:rendering.live

ViewHelper to find out if Neos is rendering the live website.

Implementation:TYPO3\Neos\ViewHelpers\Rendering\LiveViewHelper
Arguments
  • node (TYPO3TYPO3CRDomainModelNodeInterface, optional)
Examples

Basic usage:

<f:if condition="{neos:rendering.live()}">
  <f:then>
    Shown outside the backend.
  </f:then>
  <f:else>
    Shown in the backend.
  </f:else>
</f:if>

Expected result:

Shown in the backend.
neos:standaloneView

A View Helper to render a fluid template based on the given template path and filename.

This will just set up a standalone Fluid view and render the template found at the given path and filename. Any arguments passed will be assigned to that template, the rendering result is returned.

Implementation:TYPO3\Neos\ViewHelpers\StandaloneViewViewHelper
Arguments
  • templatePathAndFilename (string): Path and filename of the template to render
  • arguments (array, optional): Arguments to assign to the template before rendering
Examples

Basic usage:

<neos:standaloneView templatePathAndFilename="fancyTemplatePathAndFilename" arguments="{foo: bar, quux: baz}" />

Expected result:

<some><fancy/></html
(depending on template and arguments given)
neos:uri.module

A view helper for creating links to modules.

Implementation:TYPO3\Neos\ViewHelpers\Uri\ModuleViewHelper
Arguments
  • path (string): Target module path
  • action (string, optional): Target module action
  • arguments (array, optional): Arguments
  • section (string, optional): The anchor to be added to the URI
  • format (string, optional): The requested format, e.g. “.html
  • additionalParams (array, optional): additional query parameters that won’t be prefixed like $arguments (overrule $arguments)
  • addQueryString (boolean, optional): If set, the current query parameters will be kept in the URI
  • argumentsToBeExcludedFromQueryString (array, optional): arguments to be removed from the URI. Only active if $addQueryString = TRUE
Examples

Defaults:

<link rel="some-module" href="{neos:link.module(path: 'system/useradmin')}" />

Expected result:

<link rel="some-module" href="neos/system/useradmin" />
neos:uri.node

A view helper for creating URIs pointing to nodes.

The target node can be provided as string or as a Node object; if not specified at all, the generated URI will refer to the current document node inside the TypoScript context.

When specifying the node argument as string, the following conventions apply:

``node`` starts with ``/``: The given path is an absolute node path and is treated as such. Example: /sites/acmecom/home/about/us

``node`` does not start with ``/``: The given path is treated as a path relative to the current node. Examples: given that the current node is /sites/acmecom/products/, stapler results in /sites/acmecom/products/stapler, ../about results in /sites/acmecom/about/, ./neos/info results in /sites/acmecom/products/neos/info.

``node`` starts with a tilde character (``~``): The given path is treated as a path relative to the current site node. Example: given that the current node is /sites/acmecom/products/, ~/about/us results in /sites/acmecom/about/us, ~ results in /sites/acmecom.

Implementation:TYPO3\Neos\ViewHelpers\Uri\NodeViewHelper
Arguments
  • node (mixed, optional): A node object or a string node path (absolute or relative) or NULL to resolve the current document node
  • format (string, optional): Format to use for the URL, for example “html” or “json
  • absolute (boolean, optional): If set, an absolute URI is rendered
  • arguments (array, optional): Additional arguments to be passed to the UriBuilder (for example pagination parameters)
  • section (string, optional)
  • addQueryString (boolean, optional): If set, the current query parameters will be kept in the URI
  • argumentsToBeExcludedFromQueryString (array, optional): arguments to be removed from the URI. Only active if $addQueryString = TRUE
  • baseNodeName (string, optional): The name of the base node inside the TypoScript context to use for the ContentContext or resolving relative paths
  • resolveShortcuts (boolean, optional): INTERNAL Parameter - if FALSE, shortcuts are not redirected to their target. Only needed on rare backend occasions when we want to link to the shortcut itself.
Examples

Default:

<neos:uri.node />

Expected result:

homepage/about.html
(depending on current workspace, current node, format etc.)

Generating an absolute URI:

<neos:uri.node absolute="{true"} />

Expected result:

http://www.example.org/homepage/about.html
(depending on current workspace, current node, format, host etc.)

Target node given as absolute node path:

<neos:uri.node node="/sites/acmecom/about/us" />

Expected result:

about/us.html
(depending on current workspace, current node, format etc.)

Target node given as relative node path:

<neos:uri.node node="~/about/us" />

Expected result:

about/us.html
(depending on current workspace, current node, format etc.)

Content Repository ViewHelper Reference

This reference was automatically generated from code on 2016-06-07

PaginateViewHelper

This ViewHelper renders a Pagination of nodes.

Implementation:TYPO3\TYPO3CR\ViewHelpers\Widget\PaginateViewHelper
Arguments
  • as (string): Variable name for the result set
  • parentNode (TYPO3TYPO3CRDomainModelNodeInterface, optional): The parent node of the child nodes to show (instead of specifying the specific node set)
  • nodes (array, optional): The specific collection of nodes to use for this paginator (instead of specifying the parentNode)
  • nodeTypeFilter (string, optional): A node type (or more complex filter) to filter for in the results
  • configuration (array, optional): Additional configuration
  • widgetId (string, optional): Unique identifier of the widget instance

TypoScript ViewHelper Reference

This reference was automatically generated from code on 2016-06-07

ts:render

Render a TypoScript object with a relative TypoScript path, optionally pushing new variables onto the TypoScript context.

Implementation:TYPO3\TypoScript\ViewHelpers\RenderViewHelper
Arguments
  • path (string): Relative TypoScript path to be rendered
  • context (array, optional): Additional context variables to be set.
  • typoScriptPackageKey (string, optional): The key of the package to load TypoScript from, if not from the current context.
  • typoScriptFilePathPattern (string, optional): Resource pattern to load TypoScript from. Defaults to: resource://@package/Private/TypoScript/
Examples

Simple:

TypoScript:
some.given {
        path = TYPO3.TypoScript:Template
        
}
ViewHelper:
<ts:render path="some.given.path" />

Expected result:

(the evaluated TypoScript, depending on the given path)

TypoScript from a foreign package:

<ts:render path="some.given.path" typoScriptPackageKey="Acme.Bookstore" />

Expected result:

(the evaluated TypoScript, depending on the given path)

TypoScript Reference

TYPO3.TypoScript

This package contains general-purpose TypoScript objects, which are usable both within Neos and standalone.

TYPO3.TypoScript:Array

Render multiple nested definitions and concatenate the results.

[key]:(string) A nested definition (simple value, expression or object) that evaluates to a string
[key].@ignoreProperties:
 (array) A list of properties to ignore from being “rendered” during evaluation
[key].@position:
 (string/integer) Define the ordering of the nested definition

The order in which nested definitions are evaluated are specified using their @position meta property. For this argument, the following sort order applies:

  • start [priority] positions. The higher the priority, the earlier the object is added. If no priority is given, the element is sorted after all start elements with a priority.
  • [numeric ordering] positions, ordered ascending.
  • end [priority] positions. The higher the priority, the later the element is added. If no priority is given, the element is sorted before all end elements with a priority.

Furthermore, you can specify that an element should be inserted before or after a given other named element, using before and after syntax as follows:

  • before [namedElement] [optionalPriority]: add this element before namedElement; the higher the priority the more in front of namedElement we will add it if multiple before [namedElement] statements exist. Statements without [optionalPriority] are added the farthest before the element.

    If [namedElement] does not exist, the element is added after all start positions.

  • after [namedElement] [optionalPriority]: add this element after namedElement; the higher the priority the more closely after namedElement we will add it if multiple after [namedElement] statements exist. Statements without [optionalPriority] are added farthest after the element.

    If [namedElement] does not exist, the element is added before all all end positions.

Example Ordering:

# in this example, we would not need to use any @position property;
# as the default (document order) would then be used. However, the
# order (o1 ... o9) is *always* fixed, no matter in which order the
# individual statements are defined.

myArray = TYPO3.TypoScript:Array {
        o1 = TYPO3.Neos.NodeTypes:Text
        o1.@position = 'start 12'
        o2 = TYPO3.Neos.NodeTypes:Text
        o2.@position = 'start 5'
        o2 = TYPO3.Neos.NodeTypes:Text
        o2.@position = 'start'

        o3 = TYPO3.Neos.NodeTypes:Text
        o3.@position = '10'
        o4 = TYPO3.Neos.NodeTypes:Text
        o4.@position = '20'

        o5 = TYPO3.Neos.NodeTypes:Text
        o5.@position = 'before o6'

        o6 = TYPO3.Neos.NodeTypes:Text
        o6.@position = 'end'
        o7 = TYPO3.Neos.NodeTypes:Text
        o7.@position = 'end 20'
        o8 = TYPO3.Neos.NodeTypes:Text
        o8.@position = 'end 30'

        o9 = TYPO3.Neos.NodeTypes:Text
        o9.@position = 'after o8'
}

If no @position property is defined, the array key is used. However, we suggest to use @position and meaningful keys in your application, and not numeric ones.

Example of numeric keys (discouraged):

myArray = TYPO3.TypoScript:Array {
        10 = TYPO3.Neos.NodeTypes:Text
        20 = TYPO3.Neos.NodeTypes:Text
}
TYPO3.TypoScript:Collection

Render each item in collection using itemRenderer.

collection:(array/Iterable, required) The array or iterable to iterate over
itemName:(string, defaults to item) Context variable name for each item
itemKey:(string) Context variable name for each item key, when working with array
iterationName:(string) If set, a context variable with iteration information will be availble under the given name: index (zero-based), cycle (1-based), isFirst, isLast
itemRenderer:(string) The renderer definition (simple value, expression or object) will be called once for every collection element, and its results will be concatenated

Example using an object itemRenderer:

myCollection = TYPO3.TypoScript:Collection {
        collection = ${[1, 2, 3]}
        itemName = 'element'
        itemRenderer = TYPO3.TypoScript:Template {
                templatePath = 'resource://...'
                element = ${element}
        }
}

Example using an expression itemRenderer:

myCollection = TYPO3.TypoScript:Collection {
        collection = ${[1, 2, 3]}
        itemName = 'element'
        itemRenderer = ${element * 2}
}
TYPO3.TypoScript:Case

Conditionally evaluate nested definitions.

Evaluates all nested definitions until the first condition evaluates to TRUE. The Case object will evaluate to a result using either renderer, renderPath or type on the matching definition.

[key]:A matcher definition
[key].condition:
 (boolean, required) A simple value, expression or object that will be used as a condition for this matcher
[key].type:(string) Object type to render (as string)
[key].element.*:
 (mixed) Properties for the rendered object (when using type)
[key].renderPath:
 (string) Relative or absolute path to render, overrules type
[key].renderer:(mixed) Rendering definition (simple value, expression or object), overrules renderPath and type
[key].@position:
 (string/integer) Define the ordering of the nested definition

Simple Example:

myCase = TYPO3.TypoScript:Case {
        someCondition {
                condition = ${q(node).is('[instanceof MyNamespace:My.Special.SuperType]')}
                type = 'MyNamespace:My.Special.Type'
        }

        otherCondition {
                @position = 'start'
                condition = ${q(documentNode).property('layout') == 'special'}
                renderer = ${'<marquee>' + q(node).property('content') + '</marquee>'}
        }

        fallback {
                condition = ${true}
                renderPath = '/myPath'
        }
}

The ordering of matcher definitions can be specified with the @position property (see TYPO3.TypoScript:Array). Thus, the priority of existing matchers (e.g. the default Neos document rendering) can be changed by setting or overriding the @position property.

Note

The internal TYPO3.TypoScript:Matcher object type is used to evaluate the matcher definitions.

TYPO3.TypoScript:Debug

Shows the result of TypoScript Expressions directly.

title:(optional) Title for the debug output
plaintext:(boolean) If set true, the result will be shown as plaintext
[key]:(mixed) A nested definition (simple value, expression or object), [key] will be used as key for the resulting output

Example:

debugObject = TYPO3.TypoScript:Debug {
      title = 'Debug of hello world'

      # If only the "value"-key is given it is debugged directly,
      # otherwise all keys except "title" and "plaintext" are debugged.
      value = "hello neos world"

      # Additional values for debugging
      documentTitle = ${q(documentNode).property('title')}
      documentPath = ${documentNode.path}
}

# the value of this object is the formatted debug output of all keys given to the object
TYPO3.TypoScript:Template

Render a Fluid template specified by templatePath.

templatePath:(string, required) Path and filename for the template to be rendered, often a resource:// URI
partialRootPath:
 (string) Path where partials are found on the file system
layoutRootPath:(string) Path where layouts are found on the file system
sectionName:(string) The Fluid <f:section> to be rendered, if given
[key]:(mixed) All remaining properties are directly passed into the Fluid template as template variables

Example:

myTemplate = TYPO3.TypoScript:Template {
        templatePath = 'resource://My.Package/Private/Templates/TypoScriptObjects/MyTemplate.html'
        someDataAvailableInsideFluid = 'my data'
}

<div class="hero">
        {someDataAvailableInsideFluid}
</div>
TYPO3.TypoScript:Value

Evaluate any value as a TypoScript object

value:(mixed, required) The value to evaluate

Example:

myValue = TYPO3.TypoScript:Value {
        value = 'Hello World'
}

Note

Most of the time this can be simplified by directly assigning the value instead of using the Value object.

TYPO3.TypoScript:RawArray

Evaluate nested definitions as an array (opposed to string for TYPO3.TypoScript:Array)

[key]:(mixed) A nested definition (simple value, expression or object), [key] will be used for the resulting array key
[key].@position:
 (string/integer) Define the ordering of the nested definition

Tip

For simple cases an expression with an array literal ${[1, 2, 3]} might be easier to read

TYPO3.TypoScript:Tag

Render an HTML tag with attributes and optional body

tagName:(string) Tag name of the HTML element, defaults to div
omitClosingTag:(boolean) Whether to render the element content and the closing tag, defaults to FALSE
selfClosingTag:(boolean) Whether the tag is a self-closing tag with no closing tag. Will be resolved from tagName by default, so default HTML tags are treated correctly.
content:(string) The inner content of the element, will only be rendered if the tag is not self-closing and the closing tag is not omitted
attributes:(TYPO3.TypoScript:Attributes) Tag attributes
Example:
htmlTag = TYPO3.TypoScript:Tag {
        tagName = 'html'
        omitClosingTag = TRUE

        attributes {
                version = 'HTML+RDFa 1.1'
                xmlns = 'http://www.w3.org/1999/xhtml'
        }
}

Evaluates to:

<html version="HTML+RDFa 1.1" xmlns="http://www.w3.org/1999/xhtml">
TYPO3.TypoScript:Attributes

A TypoScript object to render HTML tag attributes. This object is used by the TYPO3.TypoScript:Tag object to render the attributes of a tag. But it’s also useful standalone to render extensible attributes in a Fluid template.

[key]:(string) A single attribute, array values are joined with whitespace. Boolean values will be rendered as an empty or absent attribute.
@allowEmpty:(boolean) Whether empty attributes (HTML5 syntax) should be used for empty, false or null attribute values
Example:
attributes = TYPO3.TypoScript:Attributes {
        foo = 'bar'
        class = TYPO3.TypoScript:RawArray {
                class1 = 'class1'
                class2 = 'class2'
        }
}

Evaluates to:

foo="bar" class="class1 class2"
Unsetting an attribute:

It’s possible to unset an attribute by assigning false or ${null} as a value. No attribute will be rendered for this case.

TYPO3.TypoScript:Http.Message

A prototype based on TYPO3.TypoScript:Array for rendering an HTTP message (response). It should be used to render documents since it generates a full HTTP response and allows to override the HTTP status code and headers.

httpResponseHead:
 (TYPO3.TypoScript:Http.ResponseHead) An HTTP response head with properties to adjust the status and headers, the position in the Array defaults to the very beginning
[key]:(string) A nested definition (see TYPO3.TypoScript:Array)
Example:
// Page extends from Http.Message
//
// prototype(TYPO3.Neos:Page) < prototype(TYPO3.TypoScript:Http.Message)
//
page = TYPO3.Neos:Page {
        httpResponseHead.headers.Content-Type = 'application/json'
}
TYPO3.TypoScript:Http.ResponseHead

A helper object to render the head of an HTTP response

statusCode:(integer) The HTTP status code for the response, defaults to 200
headers.*:(string) An HTTP header that should be set on the response, the property name (e.g. headers.Content-Type) will be used for the header name
TYPO3.TypoScript:UriBuilder

Built a URI to a controller action

package:(string) The package key (e.g. 'My.Package')
subpackage:(string) The subpackage, empty by default
controller:(string) The controller name (e.g. 'Registration')
action:(string) The action name (e.g. 'new')
arguments:(array) Arguments to the action by named key
format:(string) An optional request format (e.g. 'html')
section:(string) An optional fragment (hash) for the URI
additionalParams:
 (array) Additional URI query parameters by named key
addQueryString:(boolean) Whether to keep the query parameters of the current URI
argumentsToBeExcludedFromQueryString:
 (array) Query parameters to exclude for addQueryString
absolute:(boolean) Whether to create an absolute URI

Example:

uri = TYPO3.TypoScript:UriBuilder {
        package = 'My.Package'
        controller = 'Registration'
        action = 'new'
}
TYPO3.TypoScript:ResourceUri

Build a URI to a static or persisted resource

path:(string) Path to resource, either a path relative to Public and package or a resource:// URI
package:(string) The package key (e.g. 'My.Package')
resource:(Resource) A Resource object instead of path and package
localize:(boolean) Whether resource localization should be used, defaults to true

Example:

scriptInclude = TYPO3.TypoScript:Tag {
        tagName = 'script'
        attributes {
                src = TYPO3.TypoScript:ResourceUri {
                        path = 'resource://My.Package/Public/Scripts/App.js'
                }
        }
}

TYPO3.Neos TypoScript Objects

The TypoScript objects defined in the Neos package contain all TypoScript objects which are needed to integrate a site. Often, it contains generic TypoScript objects which do not need a particular node type to work on.

As TYPO3.Neos is the default namespace, the TypoScript objects do not need to be prefixed with TYPO3.Neos.

Page

Subclass of TYPO3.TypoScript:Http.Message, which is based on TYPO3.TypoScript:Array. Main entry point into rendering a page; responsible for rendering the <html> tag and everything inside.

doctype:(string) Defaults to <!DOCTYPE html>
htmlTag:(TYPO3.TypoScript:Tag) The opening <html> tag
htmlTag.attributes:
 (TYPO3.TypoScript:Attributes) Attributes for the <html> tag
headTag:(TYPO3.TypoScript:Tag) The opening <head> tag
head:(TYPO3.TypoScript:Array) HTML markup for the <head> tag
head.titleTag:(TYPO3.TypoScript:Tag) The <title> tag
head.javascripts:
 (TYPO3.TypoScript:Array) Script includes in the head should go here
head.stylesheets:
 (TYPO3.TypoScript:Array) Link tags for stylesheets in the head should go here
body.templatePath:
 (string) Path to a fluid template for the page body
bodyTag:(TYPO3.TypoScript:Tag) The opening <body> tag
bodyTag.attributes:
 (TYPO3.TypoScript:Attributes) Attributes for the <body> tag
body:(TYPO3.TypoScript:Template) HTML markup for the <body> tag
body.javascripts:
 (TYPO3.TypoScript:Array) Body footer JavaScript includes
body.[key]:(mixed) Body template variables
Examples:
Rendering a simple page:
page = Page
page.body.templatePath = 'resource://My.Package/Private/MyTemplate.html'
// the following line is optional, but recommended for base CSS inclusions etc
page.body.sectionName = 'main'
Rendering content in the body:

TypoScript:

page.body {
        sectionName = 'body'
        content.main = PrimaryContent {
                nodePath = 'main'
        }
}

Fluid:

<html>
        <body>
                <f:section name="body">
                        <div class="container">
                                {content.main -> f:format.raw()}
                        </div>
                </f:section>
        </body>
</html
Including stylesheets from a template section in the head:
page.head.stylesheets.mySite = TYPO3.TypoScript:Template {
        templatePath = 'resource://My.Package/Private/MyTemplate.html'
        sectionName = 'stylesheets'
}
Adding body attributes with bodyTag.attributes:
page.bodyTag.attributes.class = 'body-css-class1 body-css-class2'
ContentCollection

Render nested content from a ContentCollection node. Individual nodes are rendered using the ContentCase object.

nodePath:(string, required) The relative node path of the ContentCollection (e.g. 'main')
@context.node:(Node) The content collection node, resolved from nodePath by default
tagName:(string) Tag name for the wrapper element
attributes:(TYPO3.TypoScript:Attributes) Tag attributes for the wrapper element

Example:

page.body {
        content {
                main = PrimaryContent {
                        nodePath = 'main'
                }
                footer = ContentCollection {
                        nodePath = 'footer'
                }
        }
}
PrimaryContent

Primary content rendering, extends TYPO3.TypoScript:Case. This is a prototype that can be used from packages to extend the default content rendering (e.g. to handle specific document node types).

nodePath:(string, required) The relative node path of the ContentCollection (e.g. 'main')
default:Default matcher that renders a ContentCollection
[key]:Additional matchers (see TYPO3.TypoScript:Case)

Example for basic usage:

page.body {
        content {
                main = PrimaryContent {
                        nodePath = 'main'
                }
        }
}

Example for custom matcher:

prototype(TYPO3.Neos:PrimaryContent) {
        myArticle {
                condition = ${q(node).is('[instanceof My.Site:Article]')}
                renderer = My.Site:ArticleRenderer
        }
}
ContentCase

Render a content node, extends TYPO3.TypoScript:Case. This is a prototype that is used by the default content rendering (ContentCollection) and can be extended to add custom matchers.

default:Default matcher that renders a prototype of the same name as the node type name
[key]:Additional matchers (see TYPO3.TypoScript:Case)
Content

Base type to render content nodes, extends TYPO3.TypoScript:Template. This prototype is extended by the auto-generated TypoScript to define prototypes for each node type extending TYPO3.Neos:Content.

templatePath:(string) The template path and filename, defaults to 'resource://[packageKey]/Private/Templates/NodeTypes/[nodeType].html' (for auto-generated prototypes)
[key]:(mixed) Template variables, all node type properties are available by default (for auto-generated prototypes)
attributes:(TYPO3.TypoScript:Attributes) Extensible attributes, used in the default templates

Example:

prototype(My.Package:MyContent) < prototype(TYPO3.Neos:Content) {
        templatePath = 'resource://My.Package/Private/Templates/NodeTypes/MyContent.html'
        # Auto-generated for all node type properties
        # title = ${q(node).property('title')}
}
Plugin

Base type to render plugin content nodes or static plugins. A plugin is a Flow controller that can implement arbitrary logic.

package:(string, required) The package key (e.g. ‘My.Package’)
subpackage:(string) The subpackage, defaults to empty
controller:(array) The controller name (e.g. ‘Registration’)
action:(string) The action name, defaults to ‘index’
argumentNamespace:
 (string) Namespace for action arguments, will be resolved from node type by default
[key]:(mixed) Pass an internal argument to the controller action (access with argument name _key)

Example:

prototype(My.Site:Registration) < prototype(TYPO3.Neos:Plugin) {
        package = 'My.Site'
        controller = 'Registration'
}
DimensionsMenu

Create links to other node variants (e.g. variants of the current node in other dimensions) by using this TypoScript object.

If the dimension setting is given, the menu will only include items for this dimension, with all other configured dimension being set to the value(s) of the current node. Without any dimension being configured, all possible variants will be included.

If no node variant exists for the preset combination, a NULL node will be included in the item with a state absent.

dimension:(optional, string): name of the dimension which this menu should be based on. Example: “language”.
presets:(optional, array): If set, the presets rendered will be taken from this list of preset identifiers
includeAllPresets:
 (boolean, default false) If TRUE, include all presets, not only allowed combinations
renderHiddenInIndex:
 (boolean, default true) If TRUE, render nodes which are marked as “hidded-in-index”

In the template for the menu, each item has the following properties:

node:(Node) A node instance (with resolved shortcuts) that should be used to link to the item
state:(string) Menu state of the item: normal, current (the current node), absent
label:(string) Label of the item (the dimension preset label)
menuLevel:(integer) Menu level the item is rendered on
dimensions:(array) Dimension values of the node, indexed by dimension name
targetDimensions:
 (array) The target dimensions, indexed by dimension name and values being arrays with value, label and isPinnedDimension

Note

The DimensionMenu is an alias to DimensionsMenu, available for compatibility reasons only.

Examples

Minimal Example, outputting a menu with all configured dimension combinations:

variantMenu = TYPO3.Neos:DimensionsMenu

This example will create two menus, one for the ‘language’ and one for the ‘country’ dimension:

languageMenu = TYPO3.Neos:DimensionsMenu {
        dimension = 'language'
}
countryMenu = TYPO3.Neos:DimensionsMenu {
        dimension = 'country'
}

If you only want to render a subset of the available presets or manually define a specific order for a menu, you can override the “presets”:

languageMenu = TYPO3.Neos:DimensionsMenu {
        dimension = 'language'
        presets = ${['en_US', 'de_DE']} # no matter how many languages are defined, only these two are displayed.
}

In some cases, it can be good to ignore the availability of variants when rendering a dimensions menu. Consider a situation with two independent menus for country and language, where the following variants of a node exist (language / country):

  • english / Germany
  • german / Germany
  • english / UK

If the user selects UK, only english will be linked in the language selector. German is only available again, if the user switches back to Germany first. This can be changed by setting the includeAllPresets option:

languageMenu = TYPO3.Neos:DimensionsMenu {
        dimension = 'language'
        includeAllPresets = true
}

Now the language menu will try to find nodes for all languages, if needed the menu items will point to a different country than currently selected. The menu tries to find a node to link to by using the current preset for the language (in this example) and the default presets for any other dimensions. So if fallback rules are in place and a node can be found, it is used.

Note

The item.targetDimensions will contain the “intended” dimensions, so that information can be used to inform the user about the potentially unexpected change of dimensions when following such a link.

Only if the current node is not available at all (even after considering default presets with their fallback rules), no node be assigned (so no link will be created and the items will have the absent state.)

NodeUri

Build a URI to a node. Accepts the same arguments as the node link/uri view helpers.

node:(string/Node) A node object or a node path (relative or absolute) or empty to resolve the current document node
arguments:(array) Additional arguments to be passed to the UriBuilder (for example pagination parameters)
format:(string) An optional request format (e.g. 'html')
section:(string) An optional fragment (hash) for the URI
additionalParams:
 (array) Additional URI query parameters (overrule arguments).
argumentsToBeExcludedFromQueryString:
 (array) Query parameters to exclude for addQueryString
addQueryString:(boolean) Whether to keep current query parameters, defaults to FALSE
absolute:(boolean) Whether to create an absolute URI, defaults to FALSE
baseNodeName:(string) Base node context variable name (for relative paths), defaults to 'documentNode'

Example:

nodeLink = TYPO3.Neos:NodeUri {
        node = ${q(node).parent().get(0)}
}
ImageUri

Get a URI to a (thumbnail) image for an asset.

asset:(Asset) An asset object (Image, ImageInterface or other AssetInterface)
width:(integer) Desired width of the image
maximumWidth:(integer) Desired maximum height of the image
height:(integer) Desired height of the image
maximumHeight:(integer) Desired maximum width of the image
allowCropping:(boolean) Whether the image should be cropped if the given sizes would hurt the aspect ratio, defaults to FALSE
allowUpScaling:(boolean) Whether the resulting image size might exceed the size of the original image, defaults to FALSE

Example:

logoUri = TYPO3.Neos:ImageUri {
        asset = ${q(node).property('image')}
        width = 100
        height = 100
        allowCropping = TRUE
        allowUpScaling = TRUE
}
ImageTag

Render an image tag for an asset.

*:All ImageUri properties
attributes:(TYPO3.TypoScript:Attributes) Image tag attributes

Example:

logoImage = TYPO3.Neos:ImageTag {
        asset = ${q(node).property('image')}
        maximumWidth = 400
        attributes.alt = 'A company logo'
}
ConvertUris

Convert internal node and asset URIs (node://... or asset://...) in a string to public URIs and allows for overriding the target attribute for external links and resource links.

value:(string) The string value, defaults to the value context variable to work as a processor by default
node:(Node) The current node as a reference, defaults to the node context variable
externalLinkTarget:
 (string) Override the target attribute for external links, defaults to _blank. Can be disabled with an empty value.
resourceLinkTarget:
 (string) Override the target attribute for resource links, defaults to _blank. Can be disabled with an empty value.
forceConversion:
 (boolean) Whether to convert URIs in a non-live workspace, defaults to FALSE
absolute:(boolean) Can be used to convert node URIs to absolute links, defaults to FALSE

Example:

prototype(My.Site:Special.Type) {
        title.@process.convertUris = TYPO3.Neos:ConvertUris
}
ContentElementWrapping

Processor to augment rendered HTML code with node metadata that allows the Neos UI to select the node and show node properties in the inspector. This is especially useful if your renderer prototype is not derived from TYPO3.Neos:Content.

The processor expects being applied on HTML code with a single container tag that is augmented.

node:(Node) The node of the content element. Optional, will use the Fusion context variable node by default.

Example:

prototype(Vendor.Site:ExampleContent) {
        value = '<div>Example</div>'

        # The following line must not be removed as it adds required meta data
        # to edit content elements in the backend
        @process.contentElementWrapping = TYPO3.Neos:ContentElementWrapping {
                @position = 'end'
        }
}
ContentElementEditable

Processor to augment an HTML tag with metadata for inline editing to make a rendered representation of a property editable.

The processor expects beeing applied to an HTML tag with the content of the edited property.

node:(Node) The node of the content element. Optional, will use the Fusion context variable node by default.
property:(string) Node property that should be editable

Example:

renderer = TYPO3.TypoScript:Tag {
        tagName = 'h1'
        content = ${q(node).property('title')}
        @process.contentElementEditableWrapping = TYPO3.Neos:ContentElementEditable {
                property = 'title'
        }
}

Eel Helpers Reference

This reference was automatically generated from code on 2016-06-07

Array

Array helpers for Eel contexts

The implementation uses the JavaScript specificiation where applicable, including EcmaScript 6 proposals.

See https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array for a documentation and specification of the JavaScript implementation.

Implemented in: TYPO3\Eel\Helper\ArrayHelper

Array.concat(array1, array2, array_)

Concatenate arrays or values to a new array

  • array1 (array|mixed) First array or value
  • array2 (array|mixed) Second array or value
  • array_ (array|mixed, optional) Optional variable list of additional arrays / values

Return (array) The array with concatenated arrays or values

Array.first(array)

Get the first element of an array

  • array (array) The array

Return (mixed)

Array.indexOf(array, searchElement, fromIndex)
  • array (array)
  • searchElement (mixed)
  • fromIndex (integer, optional)

Check if an array contains a value:

Array.indexOf(myArray, 'myValue') >= 0

Return (mixed)

Array.isEmpty(array)

Check if an array is empty

  • array (array) The array

Return (boolean) TRUE if the array is empty

Array.join(array, separator)

Join values of an array with a separator

  • array (array) Array with values to join
  • separator (string, optional) A separator for the values

Return (string) A string with the joined values separated by the separator

Array.keys(array)

Get the array keys

  • array (array) The array

Return (array)

Array.last(array)

Get the last element of an array

  • array (array) The array

Return (mixed)

Array.length(array)

Get the length of an array

  • array (array) The array

Return (integer)

Array.pop(array)

Removes the last element from an array

Note: This differs from the JavaScript behavior of Array.pop which will return the popped element.

An empty array will result in an empty array again.

  • array (array)

Return (array) The array without the last element

Array.push(array, element)

Insert one or more elements at the end of an array

Allows to push multiple elements at once:

Array.push(array, e1, e2)
  • array (array)
  • element (mixed)

Return (array) The array with the inserted elements

Array.random(array)

Picks a random element from the array

  • array (array)

Return (mixed) A random entry or NULL if the array is empty

Array.reverse(array)

Returns an array in reverse order

  • array (array) The array

Return (array)

Array.shift(array)

Remove the first element of an array

Note: This differs from the JavaScript behavior of Array.shift which will return the shifted element.

An empty array will result in an empty array again.

  • array (array)

Return (array) The array without the first element

Array.shuffle(array, preserveKeys)

Shuffle an array

Randomizes entries an array with the option to preserve the existing keys. When this option is set to FALSE, all keys will be replaced

  • array (array)
  • preserveKeys (boolean, optional) Wether to preserve the keys when shuffling the array

Return (array) The shuffled array

Array.slice(array, begin, end)

Extract a portion of an indexed array

  • array (array) The array (with numeric indices)
  • begin (string)
  • end (string, optional)

Return (array)

Array.sort(array)

Sorts an array

The sorting is done first by numbers, then by characters.

Internally natsort() is used as it most closely resembles javascript’s sort(). Because there are no real associative arrays in Javascript, keys of the array will be preserved.

  • array (array)

Return (array) The sorted array

Array.splice(array, offset, length, replacements)

Replaces a range of an array by the given replacements

Allows to give multiple replacements at once:

Array.splice(array, 3, 2, 'a', 'b')
  • array (array)
  • offset (integer) Index of the first element to remove
  • length (integer, optional) Number of elements to remove
  • replacements (mixed, optional) Elements to insert instead of the removed range

Return (array) The array with removed and replaced elements

Array.unshift(array, element)

Insert one or more elements at the beginning of an array

Allows to insert multiple elements at once:

Array.unshift(array, e1, e2)
  • array (array)
  • element (mixed)

Return (array) The array with the inserted elements

Configuration

Configuration helpers for Eel contexts

Implemented in: TYPO3\Eel\Helper\ConfigurationHelper

Configuration.setting(settingPath)

Return the specified settings

Examples:

Configuration.setting('TYPO3.Flow.core.context') == 'Production'

Configuration.setting('Acme.Demo.speedMode') == 'light speed'
  • settingPath (string)

Return (mixed)

Date

Date helpers for Eel contexts

Implemented in: TYPO3\Eel\Helper\DateHelper

Date.add(date, interval)

Add an interval to a date and return a new DateTime object

  • date (DateTime)
  • interval (string|DateInterval)

Return (DateTime)

Date.dayOfMonth(dateTime)

Get the day of month of a date

  • dateTime (DateTimeInterface)

Return (integer) The day of month of the given date

Date.diff(dateA, dateB)

Get the difference between two dates as a DateInterval object

  • dateA (DateTime)
  • dateB (DateTime)

Return (DateInterval)

Date.format(date, format)

Format a date (or interval) to a string with a given format

See formatting options as in PHP date()

  • date (integer|string|DateTime|DateInterval)
  • format (string)

Return (string)

Date.hour(dateTime)

Get the hour of a date (24 hour format)

  • dateTime (DateTimeInterface)

Return (integer) The hour of the given date

Date.minute(dateTime)

Get the minute of a date

  • dateTime (DateTimeInterface)

Return (integer) The minute of the given date

Date.month(dateTime)

Get the month of a date

  • dateTime (DateTimeInterface)

Return (integer) The month of the given date

Date.now()

Get the current date and time

Examples:

Date.now().timestamp

Return (DateTime)

Date.parse(string, format)

Parse a date from string with a format to a DateTime object

  • string (string)
  • format (string)

Return (DateTime)

Date.second(dateTime)

Get the second of a date

  • dateTime (DateTimeInterface)

Return (integer) The second of the given date

Date.subtract(date, interval)

Subtract an interval from a date and return a new DateTime object

  • date (DateTime)
  • interval (string|DateInterval)

Return (DateTime)

Date.today()

Get the current date

Return (DateTime)

Date.year(dateTime)

Get the year of a date

  • dateTime (DateTimeInterface)

Return (integer) The year of the given date

Json

JSON helpers for Eel contexts

Implemented in: TYPO3\Eel\Helper\JsonHelper

Json.parse(json, associativeArrays)

JSON decode the given string

  • json (string)
  • associativeArrays (boolean, optional)

Return (mixed)

Json.stringify(value)

JSON encode the given value

  • value (mixed)

Return (string)

Math

Math helpers for Eel contexts

The implementation sticks to the JavaScript specificiation including EcmaScript 6 proposals.

See https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math for a documentation and specification of the JavaScript implementation.

Implemented in: TYPO3\Eel\Helper\MathHelper

Math.abs(x)
  • x (float, optional) A number

Return (float) The absolute value of the given value

Math.acos(x)
  • x (float) A number

Return (float) The arccosine (in radians) of the given value

Math.acosh(x)
  • x (float) A number

Return (float) The hyperbolic arccosine (in radians) of the given value

Math.asin(x)
  • x (float) A number

Return (float) The arcsine (in radians) of the given value

Math.asinh(x)
  • x (float) A number

Return (float) The hyperbolic arcsine (in radians) of the given value

Math.atan(x)
  • x (float) A number

Return (float) The arctangent (in radians) of the given value

Math.atan2(y, x)
  • y (float) A number
  • x (float) A number

Return (float) The arctangent of the quotient of its arguments

Math.atanh(x)
  • x (float) A number

Return (float) The hyperbolic arctangent (in radians) of the given value

Math.cbrt(x)
  • x (float) A number

Return (float) The cube root of the given value

Math.ceil(x)
  • x (float) A number

Return (float) The smallest integer greater than or equal to the given value

Math.cos(x)
  • x (float) A number given in radians

Return (float) The cosine of the given value

Math.cosh(x)
  • x (float) A number

Return (float) The hyperbolic cosine of the given value

Math.exp(x)
  • x (float) A number

Return (float) The power of the Euler’s constant with the given value (e^x)

Math.expm1(x)
  • x (float) A number

Return (float) The power of the Euler’s constant with the given value minus 1 (e^x - 1)

Math.floor(x)
  • x (float) A number

Return (float) The largest integer less than or equal to the given value

Math.getE()

Return (float) Euler’s constant and the base of natural logarithms, approximately 2.718

Math.getLN10()

Return (float) Natural logarithm of 10, approximately 2.303

Math.getLN2()

Return (float) Natural logarithm of 2, approximately 0.693

Math.getLOG10E()

Return (float) Base 10 logarithm of E, approximately 0.434

Math.getLOG2E()

Return (float) Base 2 logarithm of E, approximately 1.443

Math.getPI()

Return (float) Ratio of the circumference of a circle to its diameter, approximately 3.14159

Math.getSQRT1_2()

Return (float) Square root of 1/2; equivalently, 1 over the square root of 2, approximately 0.707

Math.getSQRT2()

Return (float) Square root of 2, approximately 1.414

Math.hypot(x, y, z_)
  • x (float) A number
  • y (float) A number
  • z_ (float, optional) Optional variable list of additional numbers

Return (float) The square root of the sum of squares of the arguments

Math.isFinite(x)

Test if the given value is a finite number

This is equivalent to the global isFinite() function in JavaScript.

  • x (mixed) A value

Return (boolean) TRUE if the value is a finite (not NAN) number

Math.isInfinite(x)

Test if the given value is an infinite number (INF or -INF)

This function has no direct equivalent in JavaScript.

  • x (mixed) A value

Return (boolean) TRUE if the value is INF or -INF

Math.isNaN(x)

Test if the given value is not a number (either not numeric or NAN)

This is equivalent to the global isNaN() function in JavaScript.

  • x (mixed) A value

Return (boolean) TRUE if the value is not a number

Math.log(x)
  • x (float) A number

Return (float) The natural logarithm (base e) of the given value

Math.log10(x)
  • x (float) A number

Return (float) The base 10 logarithm of the given value

Math.log1p(x)
  • x (float) A number

Return (float) The natural logarithm (base e) of 1 + the given value

Math.log2(x)
  • x (float) A number

Return (float) The base 2 logarithm of the given value

Math.max(x, y_)
  • x (float, optional) A number
  • y_ (float, optional) Optional variable list of additional numbers

Return (float) The largest of the given numbers (zero or more)

Math.min(x, y_)
  • x (float, optional) A number
  • y_ (float, optional) Optional variable list of additional numbers

Return (float) The smallest of the given numbers (zero or more)

Math.pow(x, y)

Calculate the power of x by y

  • x (float) The base
  • y (float) The exponent

Return (float) The base to the exponent power (x^y)

Math.random()

Get a random foating point number between 0 (inclusive) and 1 (exclusive)

That means a result will always be less than 1 and greater or equal to 0, the same way Math.random() works in JavaScript.

See Math.randomInt(min, max) for a function that returns random integer numbers from a given interval.

Return (float) A random floating point number between 0 (inclusive) and 1 (exclusive), that is from [0, 1)

Math.randomInt(min, max)

Get a random integer number between a min and max value (inclusive)

That means a result will always be greater than or equal to min and less than or equal to max.

  • min (integer) The lower bound for the random number (inclusive)
  • max (integer) The upper bound for the random number (inclusive)

Return (integer) A random number between min and max (inclusive), that is from [min, max]

Math.round(subject, precision)

Rounds the subject to the given precision

The precision defines the number of digits after the decimal point. Negative values are also supported (-1 rounds to full 10ths).

  • subject (float) The value to round
  • precision (integer, optional) The precision (digits after decimal point) to use, defaults to 0

Return (float) The rounded value

Math.sign(x)

Get the sign of the given number, indicating whether the number is positive, negative or zero

  • x (integer|float) The value

Return (integer) -1, 0, 1 depending on the sign or NAN if the given value was not numeric

Math.sin(x)
  • x (float) A number given in radians

Return (float) The sine of the given value

Math.sinh(x)
  • x (float) A number

Return (float) The hyperbolic sine of the given value

Math.sqrt(x)
  • x (float) A number

Return (float) The square root of the given number

Math.tan(x)
  • x (float) A number given in radians

Return (float) The tangent of the given value

Math.tanh(x)
  • x (float) A number

Return (float) The hyperbolic tangent of the given value

Math.trunc(x)

Get the integral part of the given number by removing any fractional digits

This function doesn’t round the given number but merely calls ceil(x) or floor(x) depending on the sign of the number.

  • x (float) A number

Return (integer) The integral part of the given number

Neos.Array

Some Functional Programming Array helpers for Eel contexts

These helpers are WORK IN PROGRESS and NOT STABLE YET

Implemented in: TYPO3\Neos\TypoScript\Helper\ArrayHelper

Neos.Array.filter(set, filterProperty)

Filter an array of objects, by only keeping the elements where each object’s $filterProperty evaluates to TRUE.

  • set (array|Collection)
  • filterProperty (string)

Return (array)

Neos.Array.filterNegated(set, filterProperty)

Filter an array of objects, by only keeping the elements where each object’s $filterProperty evaluates to FALSE.

  • set (array|Collection)
  • filterProperty (string)

Return (array)

Neos.Array.groupBy(set, groupingKey)

The input is assumed to be an array or Collection of objects. Groups this input by the $groupingKey property of each element.

  • set (array|Collection)
  • groupingKey (string)

Return (array)

Neos.Caching

Caching helper to make cache tag generation easier.

Implemented in: TYPO3\Neos\TypoScript\Helper\CachingHelper

Neos.Caching.descendantOfTag(nodes)

Generate a @cache entry tag for descendants of a node, an array of nodes or a FlowQuery result A cache entry with this tag will be flushed whenever a node (for any variant) that is a descendant (child on any level) of one of the given nodes is updated.

  • nodes (mixed) (A single Node or array or Traversable of Nodes)

Return (array)

Neos.Caching.nodeTag(nodes)

Generate a @cache entry tag for a single node, array of nodes or a FlowQuery result A cache entry with this tag will be flushed whenever one of the given nodes (for any variant) is updated.

  • nodes (mixed) (A single Node or array or Traversable of Nodes)

Return (array)

Neos.Caching.nodeTypeTag(nodeType)

Generate an @cache entry tag for a node type A cache entry with this tag will be flushed whenever a node (for any variant) that is of the given node type (including inheritance) is updated.

  • nodeType (NodeType)

Return (string)

Neos.Node

Eel helper for TYPO3CR Nodes

Implemented in: TYPO3\Neos\TypoScript\Helper\NodeHelper

Neos.Node.nearestContentCollection(node, nodePath)

Check if the given node is already a collection, find collection by nodePath otherwise, throw exception if no content collection could be found

  • node (NodeInterface)
  • nodePath (string)

Return (NodeInterface)

Neos.Rendering

Render Content Dimension Names, Node Labels

These helpers are WORK IN PROGRESS and NOT STABLE YET

Implemented in: TYPO3\Neos\TypoScript\Helper\RenderingHelper

Neos.Rendering.injectConfigurationManager(configurationManager)
  • configurationManager (ConfigurationManager)

Return (void)

Neos.Rendering.labelForNodeType(nodeTypeName)

Render the label for the given $nodeTypeName

  • nodeTypeName (string)

Return (string)

Neos.Rendering.renderDimensions(dimensions)

Render a human-readable description for the passed $dimensions

  • dimensions (array)

Return (string)

Security

Helper for security related information

Implemented in: TYPO3\Eel\Helper\SecurityHelper

Security.getAccount()

Get the account of the first authenticated token.

Return (TYPO3FlowSecurityAccount|NULL)

Security.hasRole(roleIdentifier)

Returns TRUE, if at least one of the currently authenticated accounts holds a role with the given identifier, also recursively.

  • roleIdentifier (string) The string representation of the role to search for

Return (boolean) TRUE, if a role with the given string representation was found

String

String helpers for Eel contexts

Implemented in: TYPO3\Eel\Helper\StringHelper

String.charAt(string, index)

Get the character at a specific position

Example:

String.charAt("abcdefg", 5) == "f"
  • string (string) The input string
  • index (integer) The index to get

Return (string) The character at the given index

String.crop(string, maximumCharacters, suffix)

Crop a string to maximumCharacters length, optionally appending suffix if cropping was necessary.

  • string (string) The input string
  • maximumCharacters (integer) Number of characters where cropping should happen
  • suffix (string, optional) Suffix to be appended if cropping was necessary

Return (string) The cropped string

String.cropAtSentence(string, maximumCharacters, suffix)

Crop a string to maximumCharacters length, taking sentences into account, optionally appending suffix if cropping was necessary.

  • string (string) The input string
  • maximumCharacters (integer) Number of characters where cropping should happen
  • suffix (string, optional) Suffix to be appended if cropping was necessary

Return (string) The cropped string

String.cropAtWord(string, maximumCharacters, suffix)

Crop a string to maximumCharacters length, taking words into account, optionally appending suffix if cropping was necessary.

  • string (string) The input string
  • maximumCharacters (integer) Number of characters where cropping should happen
  • suffix (string, optional) Suffix to be appended if cropping was necessary

Return (string) The cropped string

String.endsWith(string, search, position)

Test if a string ends with the given search string

Example:

String.endsWith('Hello, World!', 'World!') == true
  • string (string) The string
  • search (string) A string to search
  • position (integer, optional) Optional position for limiting the string

Return (boolean) TRUE if the string ends with the given search

String.firstLetterToLowerCase(string)

Lowercase the first letter of a string

Example:

String.firstLetterToLowerCase('CamelCase') == 'camelCase'
  • string (string) The input string

Return (string) The string with the first letter in lowercase

String.firstLetterToUpperCase(string)

Uppercase the first letter of a string

Example:

String.firstLetterToUpperCase('hello world') == 'Hello world'
  • string (string) The input string

Return (string) The string with the first letter in uppercase

String.htmlSpecialChars(string, preserveEntities)

Convert special characters to HTML entities

  • string (string) The string to convert
  • preserveEntities (boolean, optional) true if entities should not be double encoded

Return (string) The converted string

String.indexOf(string, search, fromIndex)

Find the first position of a substring in the given string

Example:

String.indexOf("Blue Whale", "Blue") == 0
  • string (string) The input string
  • search (string) The substring to search for
  • fromIndex (integer, optional) The index where the search should start, defaults to the beginning

Return (integer) The index of the substring (>= 0) or -1 if the substring was not found

String.isBlank(string)

Test if the given string is blank (empty or consists of whitespace only)

Examples:

String.isBlank('') == true
String.isBlank('  ') == true
  • string (string) The string to test

Return (boolean) true if the given string is blank

String.lastIndexOf(string, search, toIndex)

Find the last position of a substring in the given string

Example:

String.lastIndexOf("Developers Developers Developers!", "Developers") == 22
  • string (string) The input string
  • search (string) The substring to search for
  • toIndex (integer, optional) The position where the backwards search should start, defaults to the end

Return (integer) The last index of the substring (>=0) or -1 if the substring was not found

String.length(string)

Get the length of a string

  • string (string) The input string

Return (integer) Length of the string

String.md5(string)

Calculate the MD5 checksum of the given string

  • string (string) The string to hash

Return (string) The MD5 hash of string

String.pregMatch(string, pattern)

Match a string with a regular expression (PREG style)

  • string (string)
  • pattern (string)

Return (array) The matches as array or NULL if not matched

String.pregReplace(string, pattern, replace)

Replace occurrences of a search string inside the string using regular expression matching (PREG style)

  • string (string)
  • pattern (string)
  • replace (string)

Return (string) The string with all occurrences replaced

String.rawUrlDecode(string)

Decode the string from URLs according to RFC 3986

  • string (string) The string to decode

Return (string) The decoded string

String.rawUrlEncode(string)

Encode the string for URLs according to RFC 3986

  • string (string) The string to encode

Return (string) The encoded string

String.replace(string, search, replace)

Replace occurrences of a search string inside the string

Note: this method does not perform regular expression matching, @see pregReplace().

  • string (string)
  • search (string)
  • replace (string)

Return (string) The string with all occurrences replaced

String.split(string, separator, limit)

Split a string by a separator

Node: This implementation follows JavaScript semantics without support of regular expressions.

  • string (string) The string to split
  • separator (string, optional) The separator where the string should be splitted
  • limit (integer, optional) The maximum amount of items to split

Return (array) An array of the splitted parts, excluding the separators

String.startsWith(string, search, position)

Test if a string starts with the given search string

Examples:

String.startsWith('Hello world!', 'Hello') == true
String.startsWith('My hovercraft is full of...', 'Hello') == false
String.startsWith('My hovercraft is full of...', 'hovercraft', 3) == true
  • string (string) The input string
  • search (string) The string to search for
  • position (integer, optional) The position to test (defaults to the beginning of the string)

Return (boolean)

String.stripTags(string)

Strip all HTML tags from the given string

Example:

String.stripTags('<a href="#">Some link</a>') == 'Some link'

This is a wrapper for the strip_tags() PHP function.

  • string (string) The string to strip

Return (string) The string with tags stripped

String.substr(string, start, length)

Return the characters in a string from start up to the given length

This implementation follows the JavaScript specification for “substr”.

Examples:

String.substr('Hello, World!', 7, 5) == 'World'
String.substr('Hello, World!', 7) == 'World!'
String.substr('Hello, World!', -6) == 'World!'
  • string (string) A string
  • start (integer) Start offset
  • length (integer, optional) Maximum length of the substring that is returned

Return (string) The substring

String.substring(string, start, end)

Return the characters in a string from a start index to an end index

This implementation follows the JavaScript specification for “substring”.

Examples:

String.substring('Hello, World!', 7, 12) == 'World'
String.substring('Hello, World!', 7) == 'World!'
  • string (string)
  • start (integer) Start index
  • end (integer, optional) End index

Return (string) The substring

String.toBoolean(string)

Convert a string to boolean

A value is true, if it is either the string "TRUE" or "true" or the number 1.

  • string (string) The string to convert

Return (boolean) The boolean value of the string (true or false)

String.toFloat(string)

Convert a string to float

  • string (string) The string to convert

Return (float) The float value of the string

String.toInteger(string)

Convert a string to integer

  • string (string) The string to convert

Return (integer) The converted string

String.toLowerCase(string)

Lowercase a string

  • string (string) The input string

Return (string) The string in lowercase

String.toString(value)

Convert the given value to a string

  • value (mixed) The value to convert (must be convertible to string)

Return (string) The string value

String.toUpperCase(string)

Uppercase a string

  • string (string) The input string

Return (string) The string in uppercase

String.trim(string, charlist)

Trim whitespace at the beginning and end of a string

  • string (string) The string to trim
  • charlist (string, optional) List of characters that should be trimmed, defaults to whitespace

Return (string) The trimmed string

Translation

Translation helpers for Eel contexts

Implemented in: TYPO3\Flow\I18n\EelHelper\TranslationHelper

Translation.id(id)

Start collection of parameters for translation by id

  • id (string) Id to use for finding translation (trans-unit id in XLIFF)

Return (TranslationParameterToken)

Translation.translate(id, originalLabel, arguments, source, package, quantity, locale)

Get the translated value for an id or original label

If only id is set and contains a translation shorthand string, translate according to that shorthand

In all other cases:

Replace all placeholders with corresponding values if they exist in the translated label.

  • id (string) Id to use for finding translation (trans-unit id in XLIFF)
  • originalLabel (string, optional) The original translation value (the untranslated source string).
  • arguments (array, optional) Numerically indexed array of values to be inserted into placeholders
  • source (string, optional) Name of file with translations
  • package (string, optional) Target package key. If not set, the current package key will be used
  • quantity (mixed, optional) A number to find plural form for (float or int), NULL to not use plural forms
  • locale (string, optional) An identifier of locale to use (NULL for use the default locale)

Return (string) Translated label or source label / ID key

Translation.value(value)

Start collection of parameters for translation by original label

  • value (string)

Return (TranslationParameterToken)

Type

Type helper for Eel contexts

Implemented in: TYPO3\Eel\Helper\TypeHelper

Type.className(variable)

Get the class name of the given variable or NULL if it wasn’t an object

  • variable (object)

Return (string|NULL)

Type.getType(variable)

Get the variable type

  • variable (mixed)

Return (string)

Type.instance(variable, expectedObjectType)

Is the given variable of the provided object type.

  • variable (mixed)
  • expectedObjectType (string)

Return (boolean)

Type.isArray(variable)

Is the given variable an array.

  • variable (mixed)

Return (boolean)

Type.isBoolean(variable)

Is the given variable boolean.

  • variable (mixed)

Return (boolean)

Type.isFloat(variable)

Is the given variable a float.

  • variable (mixed)

Return (boolean)

Type.isInteger(variable)

Is the given variable an integer.

  • variable (mixed)

Return (boolean)

Type.isNumeric(variable)

Is the given variable numeric.

  • variable (mixed)

Return (boolean)

Type.isObject(variable)

Is the given variable an object.

  • variable (mixed)

Return (boolean)

Type.isScalar(variable)

Is the given variable a scalar.

  • variable (mixed)

Return (boolean)

Type.isString(variable)

Is the given variable a string.

  • variable (mixed)

Return (boolean)

Type.typeof(variable)

Get the variable type

  • variable (mixed)

Return (string)

FlowQuery Operation Reference

This reference was automatically generated from code on 2016-07-20

add

Add another $flowQuery object to the current one.

Implementation:TYPO3\Eel\FlowQuery\Operations\AddOperation
Priority:1
Final:No
Returns:void

cacheLifetime

“cacheLifetime” operation working on TYPO3CR nodes. Will get the minimum of all allowed cache lifetimes for the nodes in the current FlowQuery context. This means it will evaluate to the nearest future value of the hiddenBeforeDateTime or hiddenAfterDateTime properties of all nodes in the context. If none are set or all values are in the past it will evaluate to NULL.

To include already hidden nodes (with a hiddenBeforeDateTime value in the future) in the result, also invisible nodes have to be included in the context. This can be achieved using the “context” operation before fetching child nodes.

Example:

q(node).context({‘invisibleContentShown’: true}).children().cacheLifetime()
Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\CacheLifetimeOperation
Priority:1
Final:Yes
Returns:integer The cache lifetime in seconds or NULL if either no content collection was given or no child node had a “hiddenBeforeDateTime” or “hiddenAfterDateTime” property set

children

“children” operation working on TYPO3CR nodes. It iterates over all context elements and returns all child nodes or only those matching the filter expression specified as optional argument.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\ChildrenOperation
Priority:100
Final:No
Returns:void

children

“children” operation working on generic objects. It iterates over all context elements and returns the values of the properties given in the filter expression that has to be specified as argument or in a following filter operation.

Implementation:TYPO3\Eel\FlowQuery\Operations\Object\ChildrenOperation
Priority:1
Final:No
Returns:void

closest

“closest” operation working on TYPO3CR nodes. For each node in the context, get the first node that matches the selector by testing the node itself and traversing up through its ancestors.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\ClosestOperation
Priority:100
Final:No
Returns:void

context

“context” operation working on TYPO3CR nodes. Modifies the TYPO3CR Context of each node in the current FlowQuery context by the given properties and returns the same nodes by identifier if they can be accessed in the new Context (otherwise they will be skipped).

Example:

q(node).context({‘invisibleContentShown’: true}).children()
Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\ContextOperation
Priority:1
Final:No
Returns:void

count

Count the number of elements in the context.

If arguments are given, these are used to filter the elements before counting.

Implementation:TYPO3\Eel\FlowQuery\Operations\CountOperation
Priority:1
Final:Yes
Returns:void|integer with the number of elements

filter

This filter implementation contains specific behavior for use on TYPO3CR nodes. It will not evaluate any elements that are not instances of the NodeInterface.

The implementation changes the behavior of the instanceof operator to work on node types instead of PHP object types, so that:

[instanceof TYPO3.Neos.NodeTypes:Page]

will in fact use isOfType() on the NodeType of context elements to filter. This filter allow also to filter the current context by a given node. Anything else remains unchanged.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\FilterOperation
Priority:100
Final:No
Returns:void

filter

Filter operation, limiting the set of objects. The filter expression is expected as string argument and used to reduce the context to matching elements by checking each value against the filter.

A filter expression is written in Fizzle, a grammar inspired by CSS selectors. It has the form “[” [<value>] <operator> <operand> “]” and supports the following operators:

=
Strict equality of value and operand
!=
Strict inequality of value and operand
<
Value is less than operand
<=
Value is less than or equal to operand
>
Value is greater than operand
>=
Value is greater than or equal to operand
$=
Value ends with operand (string-based)
^=
Value starts with operand (string-based)
*=
Value contains operand (string-based)
instanceof
Checks if the value is an instance of the operand
!instanceof
Checks if the value is not an instance of the operand

For the latter the behavior is as follows: if the operand is one of the strings object, array, int(eger), float, double, bool(ean) or string the value is checked for being of the specified type. For any other strings the value is used as classname with the PHP instanceof operation to check if the value matches.

Implementation:TYPO3\Eel\FlowQuery\Operations\Object\FilterOperation
Priority:1
Final:No
Returns:void

find

“find” operation working on TYPO3CR nodes. This operation allows for retrieval of nodes specified by a path, identifier or node type (recursive).

Example (node name):

q(node).find(‘main’)

Example (relative path):

q(node).find(‘main/text1’)

Example (absolute path):

q(node).find(‘/sites/my-site/home’)

Example (identifier):

q(node).find(‘#30e893c1-caef-0ca5-b53d-e5699bb8e506’)

Example (node type):

q(node).find(‘[instanceof TYPO3.Neos.NodeTypes:Text]’)

Example (multiple node types):

q(node).find(‘[instanceof TYPO3.Neos.NodeTypes:Text],[instanceof TYPO3.Neos.NodeTypes:Image]’)

Example (node type with filter):

q(node).find(‘[instanceof TYPO3.Neos.NodeTypes:Text][text*=”Neos”]’)
Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\FindOperation
Priority:100
Final:No
Returns:void

first

Get the first element inside the context.

Implementation:TYPO3\Eel\FlowQuery\Operations\FirstOperation
Priority:1
Final:No
Returns:void

get

Get a (non-wrapped) element from the context.

If FlowQuery is used, the result is always another FlowQuery. In case you need to pass a FlowQuery result (and lazy evaluation does not work out) you can use get() to unwrap the result from the “FlowQuery envelope”.

If no arguments are given, the full context is returned. Otherwise the value contained in the context at the index given as argument is returned. If no such index exists, NULL is returned.

Implementation:TYPO3\Eel\FlowQuery\Operations\GetOperation
Priority:1
Final:Yes
Returns:mixed

has

“has” operation working on NodeInterface. Reduce the set of matched elements to those that have a child node that matches the selector or given subject.

Accepts a selector, an array, an object, a traversable object & a FlowQuery object as argument.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\HasOperation
Priority:100
Final:No
Returns:void

is

Check whether the at least one of the context elements match the given filter.

Without arguments is evaluates to TRUE if the context is not empty. If arguments are given, they are used to filter the context before evaluation.

Implementation:TYPO3\Eel\FlowQuery\Operations\IsOperation
Priority:1
Final:Yes
Returns:void|boolean

last

Get the last element inside the context.

Implementation:TYPO3\Eel\FlowQuery\Operations\LastOperation
Priority:1
Final:No
Returns:void

nextAll

“nextAll” operation working on TYPO3CR nodes. It iterates over all context elements and returns each following sibling or only those matching the filter expression specified as optional argument.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\NextAllOperation
Priority:0
Final:No
Returns:void

nextUntil

“nextUntil” operation working on TYPO3CR nodes. It iterates over all context elements and returns each following sibling until the matching sibling is found. If an optional filter expression is provided as a second argument, it only returns the nodes matching the given expression.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\NextUntilOperation
Priority:0
Final:No
Returns:void

parent

“parent” operation working on TYPO3CR nodes. It iterates over all context elements and returns each direct parent nodes or only those matching the filter expression specified as optional argument.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\ParentOperation
Priority:100
Final:No
Returns:void

parents

“parents” operation working on TYPO3CR nodes. It iterates over all context elements and returns the parent nodes or only those matching the filter expression specified as optional argument.

Implementation:TYPO3\Neos\Eel\FlowQueryOperations\ParentsOperation
Priority:100
Final:No
Returns:void

parents

“parents” operation working on TYPO3CR nodes. It iterates over all context elements and returns the parent nodes or only those matching the filter expression specified as optional argument.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\ParentsOperation
Priority:0
Final:No
Returns:void

parentsUntil

“parentsUntil” operation working on TYPO3CR nodes. It iterates over all context elements and returns the parent nodes until the matching parent is found. If an optional filter expression is provided as a second argument, it only returns the nodes matching the given expression.

Implementation:TYPO3\Neos\Eel\FlowQueryOperations\ParentsUntilOperation
Priority:100
Final:No
Returns:void

parentsUntil

“parentsUntil” operation working on TYPO3CR nodes. It iterates over all context elements and returns the parent nodes until the matching parent is found. If an optional filter expression is provided as a second argument, it only returns the nodes matching the given expression.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\ParentsUntilOperation
Priority:0
Final:No
Returns:void

prevAll

“prevAll” operation working on TYPO3CR nodes. It iterates over all context elements and returns each preceding sibling or only those matching the filter expression specified as optional argument

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\PrevAllOperation
Priority:0
Final:No
Returns:void

prevUntil

“prevUntil” operation working on TYPO3CR nodes. It iterates over all context elements and returns each preceding sibling until the matching sibling is found. If an optional filter expression is provided as a second argument, it only returns the nodes matching the given expression.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\PrevUntilOperation
Priority:0
Final:No
Returns:void

property

Used to access properties of a TYPO3CR Node. If the property mame is prefixed with _, internal node properties like start time, end time, hidden are accessed.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\PropertyOperation
Priority:100
Final:Yes
Returns:mixed

property

Access properties of an object using ObjectAccess.

Expects the name of a property as argument. If the context is empty, NULL is returned. Otherwise the value of the property on the first context element is returned.

Implementation:TYPO3\Eel\FlowQuery\Operations\Object\PropertyOperation
Priority:1
Final:Yes
Returns:mixed

siblings

“siblings” operation working on TYPO3CR nodes. It iterates over all context elements and returns all sibling nodes or only those matching the filter expression specified as optional argument.

Implementation:TYPO3\TYPO3CR\Eel\FlowQueryOperations\SiblingsOperation
Priority:100
Final:No
Returns:void

slice

Slice the current context

If no arguments are given, the full context is returned. Otherwise the values contained in the context are sliced from begin given as the first argument to an optional end in the second argument.

Implementation:TYPO3\Eel\FlowQuery\Operations\SliceOperation
Priority:1
Final:No
Returns:void

sort

“sort” operation working on TYPO3CR nodes. Sorts nodes by specified node properties.

{@inheritdoc}

First argument is the node property to sort by. Works with internal arguments (_xyz) as well. Second argument is the sort direction (ASC or DESC).

Implementation:TYPO3\Neos\Eel\FlowQueryOperations\SortOperation
Priority:1
Final:No
Returns:mixed

Command Reference

The commands in this reference are shown with their full command identifiers. On your system you can use shorter identifiers, whose availability depends on the commands available in total (to avoid overlap the shortest possible identifier is determined during runtime).

To see the shortest possible identifiers on your system as well as further commands that may be available, use:

./flow help

The following reference was automatically generated from code on 2016-09-02

Package TYPO3.FLOW

typo3.flow:cache:flush

Flush all caches

The flush command flushes all caches (including code caches) which have been registered with Flow’s Cache Manager. It also removes any session data.

If fatal errors caused by a package prevent the compile time bootstrap from running, the removal of any temporary data can be forced by specifying the option –force.

This command does not remove the precompiled data provided by frozen packages unless the –force option is used.

Options
--force
Force flushing of any temporary data
typo3.flow:cache:flushone

Flushes a particular cache by its identifier

Given a cache identifier, this flushes just that one cache. To find the cache identifiers, you can use the configuration:show command with the type set to “Caches”.

Note that this does not have a force-flush option since it’s not meant to remove temporary code data, resulting into a broken state if code files lack.

Arguments
--identifier
Cache identifier to flush cache for
Related commands
typo3.flow:cache:flush
Flush all caches
typo3.flow:configuration:show
Show the active configuration settings
typo3.flow:cache:warmup

Warm up caches

The warm up caches command initializes and fills – as far as possible – all registered caches to get a snappier response on the first following request. Apart from caches, other parts of the application may hook into this command and execute tasks which take further steps for preparing the app for the big rush.

Related commands
typo3.flow:cache:flush
Flush all caches
typo3.flow:configuration:generateschema

Generate a schema for the given configuration or YAML file.

./flow configuration:generateschema –type Settings –path TYPO3.Flow.persistence

The schema will be output to standard output.

Options
--type
Configuration type to create a schema for
--path
path to the subconfiguration separated by “.” like “TYPO3.Flow
--yaml
YAML file to create a schema for
typo3.flow:configuration:listtypes

List registered configuration types

typo3.flow:configuration:show

Show the active configuration settings

The command shows the configuration of the current context as it is used by Flow itself. You can specify the configuration type and path if you want to show parts of the configuration.

./flow configuration:show –type Settings –path TYPO3.Flow.persistence

Options
--type
Configuration type to show
--path
path to subconfiguration separated by “.” like “TYPO3.Flow
typo3.flow:configuration:validate

Validate the given configuration

Validate all configuration ./flow configuration:validate

Validate configuration at a certain subtype ./flow configuration:validate –type Settings –path TYPO3.Flow.persistence

You can retrieve the available configuration types with: ./flow configuration:listtypes

Options
--type
Configuration type to validate
--path
path to the subconfiguration separated by “.” like “TYPO3.Flow
--verbose
if TRUE, output more verbose information on the schema files which were used
typo3.flow:core:migrate

Migrate source files as needed

This will apply pending code migrations defined in packages to all packages that do not yet have those migration applied.

For every migration that has been run, it will create a commit in the package. This allows for easy inspection, rollback and use of the fixed code. If the affected package contains local changes or is not part of a git repository, the migration will be skipped. With the –force flag this behavior can be changed, but changes will only be committed if the working copy was clean before applying the migration.

Options
--status
Show the migration status, do not run migrations
--packages-path
If set, use the given path as base when looking for packages
--package-key
If set, migrate only the given package
--version
If set, execute only the migration with the given version (e.g. “20150119114100”)
--verbose
If set, notes and skipped migrations will be rendered
--force
By default packages that are not under version control or contain local changes are skipped. With this flag set changes are applied anyways (changes are not committed if there are local changes though)
Related commands
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:core:setfilepermissions

Adjust file permissions for CLI and web server access

This command adjusts the file permissions of the whole Flow application to the given command line user and webserver user / group.

Arguments
--commandline-user
User name of the command line user, for example “john
--webserver-user
User name of the webserver, for example “www-data
--webserver-group
Group name of the webserver, for example “www-data
typo3.flow:core:shell

Run the interactive Shell

The shell command runs Flow’s interactive shell. This shell allows for entering commands like through the regular command line interface but additionally supports autocompletion and a user-based command history.

typo3.flow:database:setcharset

Convert the database schema to use the given character set and collation (defaults to utf8 and utf8_unicode_ci).

This command can be used to convert the database configured in the Flow settings to the utf8 character set and the utf8_unicode_ci collation (by default, a custom collation can be given). It will only work when using the pdo_mysql driver.

Make a backup before using it, to be on the safe side. If you want to inspect the statements used for conversion, you can use the $output parameter to write them into a file. This file can be used to do the conversion manually.

For background information on this, see:

The main purpose of this is to fix setups that were created with Flow 2.3.x or earlier and whose database server did not have a default collation of utf8_unicode_ci. In those cases, the tables will have a collation that does not match the default collation of later Flow versions, potentially leading to problems when creating foreign key constraints (among others, potentially).

If you have special needs regarding the charset and collation, you can override the defaults with different ones. One thing this might be useful for is when switching to the utf8mb4 character set, see:

Note: This command is not a general purpose conversion tool. It will specifically not fix cases of actual utf8 stored in latin1 columns. For this a conversion to BLOB followed by a conversion to the proper type, charset and collation is needed instead.

Options
--character-set
Character set, defaults to utf8
--collation
Collation to use, defaults to utf8_unicode_ci
--output
A file to write SQL to, instead of executing it
--verbose
If set, the statements will be shown as they are executed
typo3.flow:doctrine:create

Create the database schema

Creates a new database schema based on the current mapping information.

It expects the database to be empty, if tables that are to be created already exist, this will lead to errors.

Options
--output
A file to write SQL to, instead of executing it
Related commands
typo3.flow:doctrine:update
Update the database schema
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:doctrine:dql

Run arbitrary DQL and display results

Any DQL queries passed after the parameters will be executed, the results will be output:

doctrine:dql –limit 10 ‘SELECT a FROM TYPO3FlowSecurityAccount a’

Options
--depth
How many levels deep the result should be dumped
--hydration-mode
One of: object, array, scalar, single-scalar, simpleobject
--offset
Offset the result by this number
--limit
Limit the result to this number
typo3.flow:doctrine:entitystatus

Show the current status of entities and mappings

Shows basic information about which entities exist and possibly if their mapping information contains errors or not.

To run a full validation, use the validate command.

Options
--dump-mapping-data
If set, the mapping data will be output
--entity-class-name
If given, the mapping data for just this class will be output
Related commands
typo3.flow:doctrine:validate
Validate the class/table mappings
typo3.flow:doctrine:migrate

Migrate the database schema

Adjusts the database structure by applying the pending migrations provided by currently active packages.

Options
--version
The version to migrate to
--output
A file to write SQL to, instead of executing it
--dry-run
Whether to do a dry run or not
--quiet
If set, only the executed migration versions will be output, one per line
Related commands
typo3.flow:doctrine:migrationstatus
Show the current migration status
typo3.flow:doctrine:migrationexecute
Execute a single migration
typo3.flow:doctrine:migrationgenerate
Generate a new migration
typo3.flow:doctrine:migrationversion
Mark/unmark migrations as migrated
typo3.flow:doctrine:migrationexecute

Execute a single migration

Manually runs a single migration in the given direction.

Arguments
--version
The migration to execute
Options
--direction
Whether to execute the migration up (default) or down
--output
A file to write SQL to, instead of executing it
--dry-run
Whether to do a dry run or not
Related commands
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:doctrine:migrationstatus
Show the current migration status
typo3.flow:doctrine:migrationgenerate
Generate a new migration
typo3.flow:doctrine:migrationversion
Mark/unmark migrations as migrated
typo3.flow:doctrine:migrationgenerate

Generate a new migration

If $diffAgainstCurrent is TRUE (the default), it generates a migration file with the diff between current DB structure and the found mapping metadata. Otherwise an empty migration skeleton is generated.

Only includes tables/sequences matching the $filterExpression regexp when diffing models and existing schema. Include delimiters in the expression! The use of

–filter-expression ‘/^acme_com/’

would only create a migration touching tables starting with “acme_com”.

Note: A filter-expression will overrule any filter configured through the TYPO3.Flow.persistence.doctrine.migrations.ignoredTables setting

Options
--diff-against-current
Whether to base the migration on the current schema structure
--filter-expression
Only include tables/sequences matching the filter expression regexp
Related commands
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:doctrine:migrationstatus
Show the current migration status
typo3.flow:doctrine:migrationexecute
Execute a single migration
typo3.flow:doctrine:migrationversion
Mark/unmark migrations as migrated
typo3.flow:doctrine:migrationstatus

Show the current migration status

Displays the migration configuration as well as the number of available, executed and pending migrations.

Options
--show-migrations
Output a list of all migrations and their status
--show-descriptions
Show descriptions for the migrations (enables versions display)
Related commands
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:doctrine:migrationexecute
Execute a single migration
typo3.flow:doctrine:migrationgenerate
Generate a new migration
typo3.flow:doctrine:migrationversion
Mark/unmark migrations as migrated
typo3.flow:doctrine:migrationversion

Mark/unmark migrations as migrated

If all is given as version, all available migrations are marked as requested.

Arguments
--version
The migration to execute
Options
--add
The migration to mark as migrated
--delete
The migration to mark as not migrated
Related commands
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:doctrine:migrationstatus
Show the current migration status
typo3.flow:doctrine:migrationexecute
Execute a single migration
typo3.flow:doctrine:migrationgenerate
Generate a new migration
typo3.flow:doctrine:update

Update the database schema

Updates the database schema without using existing migrations.

It will not drop foreign keys, sequences and tables, unless –unsafe-mode is set.

Options
--unsafe-mode
If set, foreign keys, sequences and tables can potentially be dropped.
--output
A file to write SQL to, instead of executing the update directly
Related commands
typo3.flow:doctrine:create
Create the database schema
typo3.flow:doctrine:migrate
Migrate the database schema
typo3.flow:doctrine:validate

Validate the class/table mappings

Checks if the current class model schema is valid. Any inconsistencies in the relations between models (for example caused by wrong or missing annotations) will be reported.

Note that this does not check the table structure in the database in any way.

Related commands
typo3.flow:doctrine:entitystatus
Show the current status of entities and mappings
typo3.flow:help:help

Display help for a command

The help command displays help for a given command: ./flow help <commandIdentifier>

Options
--command-identifier
Identifier of a command for more details
typo3.flow:package:activate

Activate an available package

This command activates an existing, but currently inactive package.

Arguments
--package-key
The package key of the package to create
Related commands
typo3.flow:package:deactivate
Deactivate a package
typo3.flow:package:create

Create a new package

This command creates a new package which contains only the mandatory directories and files.

Arguments
--package-key
The package key of the package to create
Options
--package-type
The package type of the package to create
Related commands
typo3.kickstart:kickstart:package
Kickstart a new package
typo3.flow:package:deactivate

Deactivate a package

This command deactivates a currently active package.

Arguments
--package-key
The package key of the package to create
Related commands
typo3.flow:package:activate
Activate an available package
typo3.flow:package:delete

Delete an existing package

This command deletes an existing package identified by the package key.

Arguments
--package-key
The package key of the package to create
typo3.flow:package:freeze

Freeze a package

This function marks a package as frozen in order to improve performance in a development context. While a package is frozen, any modification of files within that package won’t be tracked and can lead to unexpected behavior.

File monitoring won’t consider the given package. Further more, reflection data for classes contained in the package is cached persistently and loaded directly on the first request after caches have been flushed. The precompiled reflection data is stored in the Configuration directory of the respective package.

By specifying all as a package key, all currently frozen packages are frozen (the default).

Options
--package-key
Key of the package to freeze
Related commands
typo3.flow:package:unfreeze
Unfreeze a package
typo3.flow:package:refreeze
Refreeze a package
typo3.flow:package:list

List available packages

Lists all locally available packages. Displays the package key, version and package title and its state – active or inactive.

Options
--loading-order
The returned packages are ordered by their loading order.
Related commands
typo3.flow:package:activate
Activate an available package
typo3.flow:package:deactivate
Deactivate a package
typo3.flow:package:refreeze

Refreeze a package

Refreezes a currently frozen package: all precompiled information is removed and file monitoring will consider the package exactly once, on the next request. After that request, the package remains frozen again, just with the updated data.

By specifying all as a package key, all currently frozen packages are refrozen (the default).

Options
--package-key
Key of the package to refreeze, or ‘all’
Related commands
typo3.flow:package:freeze
Freeze a package
typo3.flow:cache:flush
Flush all caches
typo3.flow:package:rescan

Rescan package availability and recreates the PackageStates configuration.

typo3.flow:package:unfreeze

Unfreeze a package

Unfreezes a previously frozen package. On the next request, this package will be considered again by the file monitoring and related services – if they are enabled in the current context.

By specifying all as a package key, all currently frozen packages are unfrozen (the default).

Options
--package-key
Key of the package to unfreeze, or ‘all’
Related commands
typo3.flow:package:freeze
Freeze a package
typo3.flow:cache:flush
Flush all caches
typo3.flow:resource:clean

Clean up resource registry

This command checks the resource registry (that is the database tables) for orphaned resource objects which don’t seem to have any corresponding data anymore (for example: the file in Data/Persistent/Resources has been deleted without removing the related Resource object).

If the TYPO3.Media package is active, this command will also detect any assets referring to broken resources and will remove the respective Asset object from the database when the broken resource is removed.

This command will ask you interactively what to do before deleting anything.

typo3.flow:resource:copy

Copy resources

This command copies all resources from one collection to another storage identified by name. The target storage must be empty and must not be identical to the current storage of the collection.

This command merely copies the binary data from one storage to another, it does not change the related Resource objects in the database in any way. Since the Resource objects in the database refer to a collection name, you can use this command for migrating from one storage to another my configuring the new storage with the name of the old storage collection after the resources have been copied.

Arguments
--source-collection
The name of the collection you want to copy the assets from
--target-collection
The name of the collection you want to copy the assets to
Options
--publish
If enabled, the target collection will be published after the resources have been copied
typo3.flow:resource:publish

Publish resources

This command publishes the resources of the given or - if none was specified, all - resource collections to their respective configured publishing targets.

Options
--collection
If specified, only resources of this collection are published. Example: ‘persistent’
typo3.flow:routing:getpath

Generate a route path

This command takes package, controller and action and displays the generated route path and the selected route:

./flow routing:getPath –format json Acme.Demo\Sub\Package

Arguments
--package
Package key and subpackage, subpackage parts are separated with backslashes
Options
--controller
Controller name, default is ‘Standard’
--action
Action name, default is ‘index’
--format
Requested Format name default is ‘html’
typo3.flow:routing:list

List the known routes

This command displays a list of all currently registered routes.

typo3.flow:routing:routepath

Route the given route path

This command takes a given path and displays the detected route and the selected package, controller and action.

Arguments
--path
The route path to resolve
Options
--method
The request method (GET, POST, PUT, DELETE, …) to simulate
typo3.flow:routing:show

Show information for a route

This command displays the configuration of a route specified by index number.

Arguments
--index
The index of the route as given by routing:list
typo3.flow:security:generatekeypair

Generate a public/private key pair and add it to the RSAWalletService

Options
--used-for-passwords
If the private key should be used for passwords
Related commands
typo3.flow:security:importprivatekey
Import a private key
typo3.flow:security:importprivatekey

Import a private key

Read a PEM formatted private key from stdin and import it into the RSAWalletService. The public key will be automatically extracted and stored together with the private key as a key pair.

You can generate the same fingerprint returned from this using these commands:

ssh-keygen -yf my-key.pem > my-key.pub ssh-keygen -lf my-key.pub

To create a private key to import using this method, you can use:

ssh-keygen -t rsa -f my-key ./flow security:importprivatekey < my-key

Again, the fingerprint can also be generated using:

ssh-keygen -lf my-key.pub

Options
--used-for-passwords
If the private key should be used for passwords
Related commands
typo3.flow:security:importpublickey
Import a public key
typo3.flow:security:generatekeypair
Generate a public/private key pair and add it to the RSAWalletService
typo3.flow:security:importpublickey

Import a public key

Read a PEM formatted public key from stdin and import it into the RSAWalletService.

Related commands
typo3.flow:security:importprivatekey
Import a private key
typo3.flow:security:showeffectivepolicy

Shows a list of all defined privilege targets and the effective permissions

Arguments
--privilege-type
The privilege type (“entity”, “method” or the FQN of a class implementing PrivilegeInterface)
Options
--roles
A comma separated list of role identifiers. Shows policy for an unauthenticated user when left empty.
typo3.flow:security:showmethodsforprivilegetarget

Shows the methods represented by the given security privilege target

If the privilege target has parameters those can be specified separated by a colon for example “parameter1:value1” “parameter2:value2”. But be aware that this only works for parameters that have been specified in the policy

Arguments
--privilege-target
The name of the privilegeTarget as stated in the policy
typo3.flow:security:showunprotectedactions

Lists all public controller actions not covered by the active security policy

typo3.flow:server:run

Run a standalone development server

Starts an embedded server, see http://php.net/manual/en/features.commandline.webserver.php Note: This requires PHP 5.4+

To change the context Flow will run in, you can set the FLOW_CONTEXT environment variable: export FLOW_CONTEXT=Development && ./flow server:run

Options
--host
The host name or IP address for the server to listen on
--port
The server port to listen on
typo3.flow:typeconverter:list

Lists all currently active and registered type converters

All active converters are listed with ordered by priority and grouped by source type first and target type second.

Package TYPO3.FLUID

typo3.fluid:documentation:generatexsd

Generate Fluid ViewHelper XSD Schema

Generates Schema documentation (XSD) for your ViewHelpers, preparing the file to be placed online and used by any XSD-aware editor. After creating the XSD file, reference it in your IDE and import the namespace in your Fluid template by adding the xmlns:* attribute(s): <html xmlns=”http://www.w3.org/1999/xhtml” xmlns:f=”http://typo3.org/ns/TYPO3/Fluid/ViewHelpers” …>

Arguments
--php-namespace
Namespace of the Fluid ViewHelpers without leading backslash (for example ‘TYPO3FluidViewHelpers’). NOTE: Quote and/or escape this argument as needed to avoid backslashes from being interpreted!
Options
--xsd-namespace
Unique target namespace used in the XSD schema (for example “http://yourdomain.org/ns/viewhelpers”). Defaults to “http://typo3.org/ns/<php namespace>”.
--target-file
File path and name of the generated XSD schema. If not specified the schema will be output to standard output.

Package TYPO3.KICKSTART

typo3.kickstart:kickstart:actioncontroller

Kickstart a new action controller

Generates an Action Controller with the given name in the specified package. In its default mode it will create just the controller containing a sample indexAction.

By specifying the –generate-actions flag, this command will also create a set of actions. If no model or repository exists which matches the controller name (for example “CoffeeRepository” for “CoffeeController”), an error will be shown.

Likewise the command exits with an error if the specified package does not exist. By using the –generate-related flag, a missing package, model or repository can be created alongside, avoiding such an error.

By specifying the –generate-templates flag, this command will also create matching Fluid templates for the actions created. This option can only be used in combination with –generate-actions.

The default behavior is to not overwrite any existing code. This can be overridden by specifying the –force flag.

Arguments
--package-key
The package key of the package for the new controller with an optional subpackage, (e.g. “MyCompany.MyPackage/Admin”).
--controller-name
The name for the new controller. This may also be a comma separated list of controller names.
Options
--generate-actions
Also generate index, show, new, create, edit, update and delete actions.
--generate-templates
Also generate the templates for each action.
--generate-related
Also create the mentioned package, related model and repository if neccessary.
--force
Overwrite any existing controller or template code. Regardless of this flag, the package, model and repository will never be overwritten.
Related commands
typo3.kickstart:kickstart:commandcontroller
Kickstart a new command controller
typo3.kickstart:kickstart:commandcontroller

Kickstart a new command controller

Creates a new command controller with the given name in the specified package. The generated controller class already contains an example command.

Arguments
--package-key
The package key of the package for the new controller
--controller-name
The name for the new controller. This may also be a comma separated list of controller names.
Options
--force
Overwrite any existing controller.
Related commands
typo3.kickstart:kickstart:actioncontroller
Kickstart a new action controller
typo3.kickstart:kickstart:documentation

Kickstart documentation

Generates a documentation skeleton for the given package.

Arguments
--package-key
The package key of the package for the documentation
typo3.kickstart:kickstart:model

Kickstart a new domain model

This command generates a new domain model class. The fields are specified as a variable list of arguments with field name and type separated by a colon (for example “title:string” “size:int” “type:MyType”).

Arguments
--package-key
The package key of the package for the domain model
--model-name
The name of the new domain model class
Options
--force
Overwrite any existing model.
Related commands
typo3.kickstart:kickstart:repository
Kickstart a new domain repository
typo3.kickstart:kickstart:package

Kickstart a new package

Creates a new package and creates a standard Action Controller and a sample template for its Index Action.

For creating a new package without sample code use the package:create command.

Arguments
--package-key
The package key, for example “MyCompany.MyPackageName
Related commands
typo3.flow:package:create
Create a new package
typo3.kickstart:kickstart:repository

Kickstart a new domain repository

This command generates a new domain repository class for the given model name.

Arguments
--package-key
The package key
--model-name
The name of the domain model class
Options
--force
Overwrite any existing repository.
Related commands
typo3.kickstart:kickstart:model
Kickstart a new domain model

Package TYPO3.MEDIA

typo3.media:media:clearthumbnails

Remove thumbnails

Removes all thumbnail objects and their resources. Optional preset parameter to only remove thumbnails matching a specific thumbnail preset configuration.

Options
--preset
Preset name, if provided only thumbnails matching that preset are cleared
typo3.media:media:createthumbnails

Create thumbnails

Creates thumbnail images based on the configured thumbnail presets. Optional preset parameter to only create thumbnails for a specific thumbnail preset configuration.

Additionally accepts a async parameter determining if the created thumbnails are generated when created.

Options
--preset
Preset name, if not provided thumbnails are created for all presets
--async
Asynchronous generation, if not provided the setting TYPO3.Media.asyncThumbnails is used
typo3.media:media:importresources

Import resources to asset management

This command detects Flow “Resource” objects which are not yet available as “Asset” objects and thus don’t appear in the asset management. The type of the imported asset is determined by the file extension provided by the Resource object.

Options
--simulate
If set, this command will only tell what it would do instead of doing it right away
typo3.media:media:renderthumbnails

Render ungenerated thumbnails

Loops over ungenerated thumbnails and renders them. Optional limit parameter to limit the amount of thumbnails to be rendered to avoid memory exhaustion.

Options
--limit
Limit the amount of thumbnails to be rendered to avoid memory exhaustion

Package TYPO3.NEOS

typo3.neos:domain:activate

Activate a domain record

Arguments
--host-pattern
The host pattern of the domain to activate
typo3.neos:domain:add

Add a domain record

Arguments
--site-node-name
The nodeName of the site rootNode, e.g. “neostypo3org
--host-pattern
The host pattern to match on, e.g. “neos.typo3.org
Options
--scheme
The scheme for linking (http/https)
--port
The port for linking (0-49151)
typo3.neos:domain:deactivate

Deactivate a domain record

Arguments
--host-pattern
The host pattern of the domain to deactivate
typo3.neos:domain:delete

Delete a domain record

Arguments
--host-pattern
The host pattern of the domain to remove
typo3.neos:domain:list

Display a list of available domain records

Options
--host-pattern
An optional host pattern to search for
typo3.neos:site:export

Export sites content (e.g. site:export –package-key &quot;Neos.Demo&quot;)

This command exports all or one specific site with all its content into an XML format.

If the package key option is given, the site(s) will be exported to the given package in the default location Resources/Private/Content/Sites.xml.

If the filename option is given, any resources will be exported to files in a folder named “Resources” alongside the XML file.

If neither the filename nor the package key option are given, the XML will be printed to standard output and assets will be embedded into the XML in base64 encoded form.

Options
--site-node
the node name of the site to be exported; if none given will export all sites
--tidy
Whether to export formatted XML
--filename
relative path and filename to the XML file to create. Any resource will be stored in a sub folder “Resources”.
--package-key
Package to store the XML file in. Any resource will be stored in a sub folder “Resources”.
--node-type-filter
Filter the node type of the nodes, allows complex expressions (e.g. “TYPO3.Neos:Page”, “!TYPO3.Neos:Page,TYPO3.Neos:Text”)
typo3.neos:site:import

Import sites content

This command allows for importing one or more sites or partial content from an XML source. The format must be identical to that produced by the export command.

If a filename is specified, this command expects the corresponding file to contain the XML structure. The filename php://stdin can be used to read from standard input.

If a package key is specified, this command expects a Sites.xml file to be located in the private resources directory of the given package (Resources/Private/Content/Sites.xml).

Options
--package-key
Package key specifying the package containing the sites content
--filename
relative path and filename to the XML file containing the sites content
typo3.neos:site:list

Display a list of available sites

typo3.neos:site:prune

Remove all content and related data - for now. In the future we need some more sophisticated cleanup.

Options
--site-node-name
Name of a site root node to clear only content of this site.
typo3.neos:user:activate

Activate a user

This command reactivates possibly expired accounts for the given user.

If an authentication provider is specified, this command will look for an account with the given username related to the given provider. Still, this command will activate all accounts of a user, once such a user has been found.

Arguments
--username
The username of the user to be activated.
Options
--authentication-provider
Name of the authentication provider to use for finding the user. Example: “Typo3BackendProvider
typo3.neos:user:addrole

Add a role to a user

This command allows for adding a specific role to an existing user.

Roles can optionally be specified as a comma separated list. For all roles provided by Neos, the role namespace “TYPO3.Neos:” can be omitted.

If an authentication provider was specified, the user will be determined by an account identified by “username” related to the given provider. However, once a user has been found, the new role will be added to all existing accounts related to that user, regardless of its authentication provider.

Arguments
--username
The username of the user
--role
Role to be added to the user, for example “TYPO3.Neos:Administrator” or just “Administrator
Options
--authentication-provider
Name of the authentication provider to use. Example: “Typo3BackendProvider
typo3.neos:user:create

Create a new user

This command creates a new user which has access to the backend user interface.

More specifically, this command will create a new user and a new account at the same time. The created account is, by default, a Neos backend account using the the “Typo3BackendProvider” for authentication. The given username will be used as an account identifier for that new account.

If an authentication provider name is specified, the new account will be created for that provider instead.

Roles for the new user can optionally be specified as a comma separated list. For all roles provided by Neos, the role namespace “TYPO3.Neos:” can be omitted.

Arguments
--username
The username of the user to be created, used as an account identifier for the newly created account
--password
Password of the user to be created
--first-name
First name of the user to be created
--last-name
Last name of the user to be created
Options
--roles
A comma separated list of roles to assign. Examples: “Editor, Acme.Foo:Reviewer
--authentication-provider
Name of the authentication provider to use for the new account. Example: “Typo3BackendProvider
typo3.neos:user:deactivate

Deactivate a user

This command deactivates a user by flagging all of its accounts as expired.

If an authentication provider is specified, this command will look for an account with the given username related to the given provider. Still, this command will deactivate all accounts of a user, once such a user has been found.

Arguments
--username
The username of the user to be deactivated.
Options
--authentication-provider
Name of the authentication provider to use for finding the user. Example: “Typo3BackendProvider
typo3.neos:user:delete

Delete a user

This command deletes an existing Neos user. All content and data directly related to this user, including but not limited to draft workspace contents, will be removed as well.

All accounts owned by the given user will be deleted.

If an authentication provider is specified, this command will look for an account with the given username related to the given provider. Specifying an authentication provider does not mean that only the account for that provider is deleted! If a user was found by the combination of username and authentication provider, all related accounts will be deleted.

Arguments
--username
The username of the user to be removed
Options
--assume-yes
Assume “yes” as the answer to the confirmation dialog
--authentication-provider
Name of the authentication provider to use. Example: “Typo3BackendProvider
typo3.neos:user:list

List all users

This command lists all existing Neos users.

typo3.neos:user:removerole

Remove a role from a user

This command allows for removal of a specific role from an existing user.

If an authentication provider was specified, the user will be determined by an account identified by “username” related to the given provider. However, once a user has been found, the role will be removed from all existing accounts related to that user, regardless of its authentication provider.

Arguments
--username
The username of the user
--role
Role to be removed from the user, for example “TYPO3.Neos:Administrator” or just “Administrator
Options
--authentication-provider
Name of the authentication provider to use. Example: “Typo3BackendProvider
typo3.neos:user:setpassword

Set a new password for the given user

This command sets a new password for an existing user. More specifically, all accounts related to the user which are based on a username / password token will receive the new password.

If an authentication provider was specified, the user will be determined by an account identified by “username” related to the given provider.

Arguments
--username
Username of the user to modify
--password
The new password
Options
--authentication-provider
Name of the authentication provider to use for finding the user. Example: “Typo3BackendProvider
typo3.neos:user:show

Shows the given user

This command shows some basic details about the given user. If such a user does not exist, this command will exit with a non-zero status code.

The user will be retrieved by looking for a Neos backend account with the given identifier (ie. the username) and then retrieving the user which owns that account. If an authentication provider is specified, this command will look for an account identified by “username” for that specific provider.

Arguments
--username
The username of the user to show. Usually refers to the account identifier of the user’s Neos backend account.
Options
--authentication-provider
Name of the authentication provider to use. Example: “Typo3BackendProvider
typo3.neos:workspace:create

Create a new workspace

This command creates a new workspace.

Arguments
--workspace
Name of the workspace, for example “christmas-campaign
Options
--base-workspace
Name of the base workspace. If none is specified, “live” is assumed.
--title
Human friendly title of the workspace, for example “Christmas Campaign
--description
A description explaining the purpose of the new workspace
--owner
The identifier of a User to own the workspace
typo3.neos:workspace:delete

Deletes a workspace

This command deletes a workspace. If you only want to empty a workspace and not delete the workspace itself, use workspace:discard instead.

Arguments
--workspace
Name of the workspace, for example “christmas-campaign
Options
--force
Delete the workspace and all of its contents
Related commands
typo3.neos:workspace:discard
Discard changes in workspace
typo3.neos:workspace:discard

Discard changes in workspace

This command discards all modified, created or deleted nodes in the specified workspace.

Arguments
--workspace
Name of the workspace, for example “user-john
Options
--verbose
If enabled, information about individual nodes will be displayed
--dry-run
If set, only displays which nodes would be discarded, no real changes are committed
typo3.neos:workspace:discardall

Discard changes in workspace &lt;b&gt;(DEPRECATED)&lt;/b&gt;

This command discards all modified, created or deleted nodes in the specified workspace.

Arguments
--workspace-name
Name of the workspace, for example “user-john
Options
--verbose
If enabled, information about individual nodes will be displayed
Related commands
typo3.neos:workspace:discard
Discard changes in workspace
typo3.neos:workspace:list

Display a list of existing workspaces

typo3.neos:workspace:publish

Publish changes of a workspace

This command publishes all modified, created or deleted nodes in the specified workspace to its base workspace. If a target workspace is specified, the content is published to that workspace instead.

Arguments
--workspace
Name of the workspace containing the changes to publish, for example “user-john
Options
--target-workspace
If specified, the content will be published to this workspace instead of the base workspace
--verbose
If enabled, some information about individual nodes will be displayed
--dry-run
If set, only displays which nodes would be published, no real changes are committed
typo3.neos:workspace:publishall

Publish changes of a workspace &lt;b&gt;(DEPRECATED)&lt;/b&gt;

This command publishes all modified, created or deleted nodes in the specified workspace to the live workspace.

Arguments
--workspace-name
Name of the workspace, for example “user-john
Options
--verbose
If enabled, information about individual nodes will be displayed
Related commands
typo3.neos:workspace:publish
Publish changes of a workspace
typo3.neos:workspace:rebase

Rebase a workspace

This command sets a new base workspace for the specified workspace. Note that doing so will put the possible changes contained in the workspace to be rebased into a different context and thus might lead to unintended results when being published.

Arguments
--workspace
Name of the workspace to rebase, for example “user-john
--base-workspace
Name of the new base workspace

Package TYPO3.NEOS.KICKSTARTER

typo3.neos.kickstarter:kickstart:site

Kickstart a new site package

This command generates a new site package with basic TypoScript and Sites.xml

Arguments
--package-key
The packageKey for your site
--site-name
The siteName of your site

Package TYPO3.TYPO3CR

typo3.typo3cr:node:autocreatechildnodes

Create missing child nodes &lt;b&gt;(DEPRECATED)&lt;/b&gt;

This is a legacy command which automatically creates missing child nodes for a node type based on the structure defined in the NodeTypes configuration.

NOTE: Usage of this command is deprecated and it will be remove eventually. Please use node:repair instead.

Options
--node-type
Node type name, if empty update all declared node types
--workspace
Workspace name, default is ‘live’
--dry-run
Don’t do anything, but report missing child nodes
Related commands
typo3.typo3cr:node:repair
Repair inconsistent nodes
typo3.typo3cr:node:repair

Repair inconsistent nodes

This command analyzes and repairs the node tree structure and individual nodes based on the current node type configuration.

It is possible to execute only one or more specific checks by providing the –skip or –only option. See the full description of checks further below for possible check identifiers.

The following checks will be performed:

Generate missing URI path segments

Generates URI path segment properties for all document nodes which don’t have a path segment set yet.

Remove content dimensions from / and /sites removeContentDimensionsFromRootAndSitesNode

Removes content dimensions from the root and sites nodes

Remove abstract and undefined node types removeAbstractAndUndefinedNodes

Will remove all nodes that has an abstract or undefined node type.

Remove orphan (parentless) nodes removeOrphanNodes

Will remove all child nodes that do not have a connection to the root node.

Remove disallowed child nodes removeDisallowedChildNodes

Will remove all child nodes that are disallowed according to the node type’s auto-create configuration and constraints.

Remove undefined node properties removeUndefinedProperties

Remove broken object references removeBrokenEntityReferences

Detects and removes references from nodes to entities which don’t exist anymore (for example Image nodes referencing ImageVariant objects which are gone for some reason).

Will remove all undefined properties according to the node type configuration.

Remove nodes with invalid dimensions removeNodesWithInvalidDimensions

Will check for and optionally remove nodes which have dimension values not matching the current content dimension configuration.

Remove nodes with invalid workspace removeNodesWithInvalidWorkspace

Will check for and optionally remove nodes which belong to a workspace which no longer exists..

Repair inconsistent node identifiers fixNodesWithInconsistentIdentifier

Will check for and optionally repair node identifiers which are out of sync with their corresponding nodes in a live workspace.

Missing child nodes createMissingChildNodes

For all nodes (or only those which match the –node-type filter specified with this command) which currently don’t have child nodes as configured by the node type’s configuration new child nodes will be created.

Reorder child nodes reorderChildNodes

For all nodes (or only those which match the –node-type filter specified with this command) which have configured child nodes, those child nodes are reordered according to the position from the parents NodeType configuration. Missing default properties addMissingDefaultValues

For all nodes (or only those which match the –node-type filter specified with this command) which currently dont have a property that have a default value configuration the default value for that property will be set.

Repair nodes with missing shadow nodes repairShadowNodes

This will reconstruct missing shadow nodes in case something went wrong in creating or publishing them. This must be used on a workspace other than live.

It searches for nodes which have a corresponding node in one of the base workspaces, have different node paths, but don’t have a corresponding shadow node with a “movedto” value.

Examples:

./flow node:repair

./flow node:repair –node-type TYPO3.Neos.NodeTypes:Page

./flow node:repair –workspace user-robert –only removeOrphanNodes,removeNodesWithInvalidDimensions

./flow node:repair –skip removeUndefinedProperties

Options
--node-type
Node type name, if empty update all declared node types
--workspace
Workspace name, default is ‘live’
--dry-run
Don’t do anything, but report actions
--cleanup
If FALSE, cleanup tasks are skipped
--skip
Skip the given check or checks (comma separated)
--only
Only execute the given check or checks (comma separated)

Validator Reference

Flow Validator Reference

This reference was automatically generated from code on 2016-06-07

AggregateBoundaryValidator

A validator which will not validate Aggregates that are lazy loaded and uninitialized. Validation over Aggregate Boundaries can hence be forced by making the relation to other Aggregate Roots eager loaded.

Note that this validator is not part of the public API and you should not use it manually.

Checks if the given value is valid according to the property validators.

Note

A value of NULL or an empty string (‘’) is considered valid

AlphanumericValidator

Validator for alphanumeric strings.

The given $value is valid if it is an alphanumeric string, which is defined as [[:alnum:]].

Note

A value of NULL or an empty string (‘’) is considered valid

BooleanValueValidator

Validator for a specific boolean value.

Checks if the given value is a specific boolean value.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • expectedValue (boolean, optional): The expected boolean value
CollectionValidator

A generic collection validator.

Checks for a collection and if needed validates the items in the collection. This is done with the specified element validator or a validator based on the given element type and validation group.

Either elementValidator or elementType must be given, otherwise validation will be skipped.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • elementValidator (string, optional): The validator type to use for the collection elements
  • elementValidatorOptions (array, optional): The validator options to use for the collection elements
  • elementType (string, optional): The type of the elements in the collection
  • validationGroups (string, optional): The validation groups to link to
CountValidator

Validator for countable things

The given value is valid if it is an array or Countable that contains the specified amount of elements.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • minimum (integer, optional): The minimum count to accept
  • maximum (integer, optional): The maximum count to accept
DateTimeRangeValidator

Validator for checking Date and Time boundaries

Adds errors if the given DateTime does not match the set boundaries.

latestDate and earliestDate may be each <time>, <start>/<duration> or <duration>/<end>, where <duration> is an ISO 8601 duration and <start> or <end> or <time> may be ‘now’ or a PHP supported format. (1)

In general, you are able to provide a timestamp or a timestamp with additional calculation. Calculations are done as described in ISO 8601 (2), with an introducing “P”. P7MT2H30M for example mean a period of 7 months, 2 hours and 30 minutes (P introduces a period at all, while a following T introduces the time-section of a period. This is not at least in order not to confuse months and minutes, both represented as M). A period is separated from the timestamp with a forward slash “/”. If the period follows the timestamp, that period is added to the timestamp; if the period precedes the timestamp, it’s subtracted. The timestamp can be one of PHP’s supported date formats (1), so also “now” is supported.

Use cases:

If you offer something that has to be manufactured and you ask for a delivery date, you might assure that this date is at least two weeks in advance; this could be done with the expression “now/P2W”. If you have a library of ancient goods and want to track a production date that is at least 5 years ago, you can express it with “P5Y/now”.

Examples:

If you want to test if a given date is at least five minutes ahead, use
earliestDate: now/PT5M
If you want to test if a given date was at least 10 days ago, use
latestDate: P10D/now
If you want to test if a given date is between two fix boundaries, just combine the latestDate and earliestDate-options:
earliestDate: 2007-03-01T13:00:00Z latestDate: 2007-03-30T13:00:00Z

Footnotes:

http://de.php.net/manual/en/datetime.formats.compound.php (1) http://en.wikipedia.org/wiki/ISO_8601#Durations (2) http://en.wikipedia.org/wiki/ISO_8601#Time_intervals (3)

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • latestDate (string, optional): The latest date to accept
  • earliestDate (string, optional): The earliest date to accept
DateTimeValidator

Validator for DateTime objects.

Checks if the given value is a valid DateTime object.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • locale (string|Locale, optional): The locale to use for date parsing
  • strictMode (boolean, optional): Use strict mode for date parsing
  • formatLength (string, optional): The format length, see DatesReader::FORMAT_LENGTH_*
  • formatType (string, optional): The format type, see DatesReader::FORMAT_TYPE_*
EmailAddressValidator

Validator for email addresses

Checks if the given value is a valid email address.

Note

A value of NULL or an empty string (‘’) is considered valid

FloatValidator

Validator for floats.

The given value is valid if it is of type float or a string matching the regular expression [0-9.e+-]

Note

A value of NULL or an empty string (‘’) is considered valid

GenericObjectValidator

A generic object validator which allows for specifying property validators.

Checks if the given value is valid according to the property validators.

Note

A value of NULL or an empty string (‘’) is considered valid

IntegerValidator

Validator for integers.

Checks if the given value is a valid integer.

Note

A value of NULL or an empty string (‘’) is considered valid

LabelValidator

A validator for labels.

Labels usually allow all kinds of letters, numbers, punctuation marks and the space character. What you don’t want in labels though are tabs, new line characters or HTML tags. This validator is for such uses.

The given value is valid if it matches the regular expression specified in PATTERN_VALIDCHARACTERS.

Note

A value of NULL or an empty string (‘’) is considered valid

LocaleIdentifierValidator

A validator for locale identifiers.

This validator validates a string based on the expressions of the Flow I18n implementation.

Is valid if the given value is a valid “locale identifier”.

Note

A value of NULL or an empty string (‘’) is considered valid

NotEmptyValidator

Validator for not empty values.

Checks if the given value is not empty (NULL, empty string, empty array or empty object that implements the Countable interface).

NumberRangeValidator

Validator for general numbers

The given value is valid if it is a number in the specified range.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • minimum (integer, optional): The minimum value to accept
  • maximum (integer, optional): The maximum value to accept
NumberValidator

Validator for general numbers.

Checks if the given value is a valid number.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • locale (string|Locale, optional): The locale to use for number parsing
  • strictMode (boolean, optional): Use strict mode for number parsing
  • formatLength (string, optional): The format length, see NumbersReader::FORMAT_LENGTH_*
  • formatType (string, optional): The format type, see NumbersReader::FORMAT_TYPE_*
RawValidator

A validator which accepts any input.

This validator is always valid.

Note

A value of NULL or an empty string (‘’) is considered valid

RegularExpressionValidator

Validator based on regular expressions.

Checks if the given value matches the specified regular expression.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • regularExpression (string): The regular expression to use for validation, used as given
StringLengthValidator

Validator for string length.

Checks if the given value is a valid string (or can be cast to a string if an object is given) and its length is between minimum and maximum specified in the validation options.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • minimum (integer, optional): Minimum length for a valid string
  • maximum (integer, optional): Maximum length for a valid string
StringValidator

Validator for strings.

Checks if the given value is a string.

Note

A value of NULL or an empty string (‘’) is considered valid

TextValidator

Validator for “plain” text.

Checks if the given value is a valid text (contains no XML tags).

Be aware that the value of this check entirely depends on the output context. The validated text is not expected to be secure in every circumstance, if you want to be sure of that, use a customized regular expression or filter on output.

See http://php.net/filter_var for details.

Note

A value of NULL or an empty string (‘’) is considered valid

UniqueEntityValidator

Validator for uniqueness of entities.

Checks if the given value is a unique entity depending on it’s identity properties or custom configured identity properties.

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • identityProperties (array, optional): List of custom identity properties.
UuidValidator

Validator for Universally Unique Identifiers.

Checks if the given value is a syntactically valid UUID.

Note

A value of NULL or an empty string (‘’) is considered valid

Media Validator Reference

This reference was automatically generated from code on 2016-06-07

ImageOrientationValidator

Validator that checks the orientation (square, portrait, landscape) of a given image.

Supported validator options are (array)allowedOrientations with one or two out of ‘square’, ‘landcape’ or ‘portrait’.

Example:

[at]Flow\Validate("$image", type="\TYPO3\Media\Validator\ImageOrientationValidator",
      options={ "allowedOrientations"={"square", "landscape"} })

this would refuse an image that is in portrait orientation, but allow landscape and square ones.

The given $value is valid if it is an TYPO3MediaDomainModelImageInterface of the configured orientation (square, portrait and/or landscape) Note: a value of NULL or empty string (‘’) is considered valid

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • allowedOrientations (array): Array of image orientations, one or two out of ‘square’, ‘landcape’ or ‘portrait’
ImageSizeValidator

Validator that checks size (resolution) of a given image

Example: [at]FlowValidate(“$image”, type=”TYPO3MediaValidatorImageSizeValidator”, options={ “minimumWidth”=150, “maximumResolution”=60000 })

The given $value is valid if it is an TYPO3MediaDomainModelImageInterface of the configured resolution Note: a value of NULL or empty string (‘’) is considered valid

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • minimumWidth (integer, optional): The minimum width of the image
  • minimumHeight (integer, optional): The minimum height of the image
  • maximumWidth (integer, optional): The maximum width of the image
  • maximumHeight (integer, optional): The maximum height of the image
  • minimumResolution (integer, optional): The minimum resolution of the image
  • maximumResolution (integer, optional): The maximum resolution of the image
ImageTypeValidator

Validator that checks the type of a given image

Example: [at]FlowValidate(“$image”, type=”TYPO3MediaValidatorImageTypeValidator”, options={ “allowedTypes”={“jpeg”, “png”} })

The given $value is valid if it is an TYPO3MediaDomainModelImageInterface of the configured type (one of the image/* IANA media subtypes)

Note: a value of NULL or empty string (‘’) is considered valid

Note

A value of NULL or an empty string (‘’) is considered valid

Arguments
  • allowedTypes (array): Allowed image types (using image/* IANA media subtypes)

Party Validator Reference

This reference was automatically generated from code on 2016-06-07

AimAddressValidator

Validator for AIM addresses.

Checks if the given value is a valid AIM name.

The AIM name has the following requirements: “It must be between 3 and 16 alphanumeric characters in length and must begin with a letter.”

Note

A value of NULL or an empty string (‘’) is considered valid

IcqAddressValidator

Validator for ICQ addresses.

Checks if the given value is a valid ICQ UIN address.

The ICQ UIN address has the following requirements: “It must be 9 numeric characters.” More information is found on: http://www.icq.com/support/icq_8/start/authorization/en

Note

A value of NULL or an empty string (‘’) is considered valid

JabberAddressValidator

Validator for Jabber addresses.

Checks if the given value is a valid Jabber name.

The Jabber address has the following structure: “name@jabber.org” More information is found on: http://tracker.phpbb.com/browse/PHPBB3-3832

Note

A value of NULL or an empty string (‘’) is considered valid

MsnAddressValidator

Validator for MSN addresses.

Checks if the given value is a valid MSN address.

The MSN address has the following structure: “name@hotmail.com, name@live.com, name@msn.com, name@outlook.com

Note

A value of NULL or an empty string (‘’) is considered valid

SipAddressValidator

Validator for Sip addresses.

Checks if the given value is a valid Sip name.

The Sip address has the following structure: “sip:+4930432343@isp.com” More information is found on: http://wiki.snom.com/Features/Dial_Plan/Regular_Expressions

Note

A value of NULL or an empty string (‘’) is considered valid

SkypeAddressValidator

Validator for Skype addresses.

Checks if the given value is a valid Skype name.

The Skype website says: “It must be between 6-32 characters, start with a letter and contain only letters and numbers (no spaces or special characters).”

Nevertheless dash and underscore are allowed as special characters. Furthermore, account names can contain a colon if they were auto-created trough a connected Microsoft or Facebook profile. In this case, the syntax is as follows: - live:john.due - Facebook:john.doe

We added period and minus as additional characters because they are suggested by Skype during registration.

Note

A value of NULL or an empty string (‘’) is considered valid

UrlAddressValidator

Validator for URL addresses.

Checks if the given value is a valid URL.

Note

A value of NULL or an empty string (‘’) is considered valid

YahooAddressValidator

Validator for Yahoo addresses.

Checks if the given value is a valid Yahoo address.

The Yahoo address has the following structure: “name@yahoo.*

Note

A value of NULL or an empty string (‘’) is considered valid

Signal Reference

Flow Signals Reference

This reference was automatically generated from code on 2016-06-07

AbstractAdvice (TYPO3\Flow\Aop\Advice\AbstractAdvice)

This class contains the following signals.

adviceInvoked

Emits a signal when an Advice is invoked

The advice is not proxyable, so the signal is dispatched manually here.

AbstractBackend (TYPO3\Flow\Persistence\Generic\Backend\AbstractBackend)

This class contains the following signals.

removedObject

Autogenerated Proxy Method

persistedObject

Autogenerated Proxy Method

ActionRequest (TYPO3\Flow\Mvc\ActionRequest)

This class contains the following signals.

requestDispatched

Autogenerated Proxy Method

AfterAdvice (TYPO3\Flow\Aop\Advice\AfterAdvice)

This class contains the following signals.

adviceInvoked

Emits a signal when an Advice is invoked

The advice is not proxyable, so the signal is dispatched manually here.

AfterReturningAdvice (TYPO3\Flow\Aop\Advice\AfterReturningAdvice)

This class contains the following signals.

adviceInvoked

Emits a signal when an Advice is invoked

The advice is not proxyable, so the signal is dispatched manually here.

AfterThrowingAdvice (TYPO3\Flow\Aop\Advice\AfterThrowingAdvice)

This class contains the following signals.

adviceInvoked

Emits a signal when an Advice is invoked

The advice is not proxyable, so the signal is dispatched manually here.

AroundAdvice (TYPO3\Flow\Aop\Advice\AroundAdvice)

This class contains the following signals.

adviceInvoked

Emits a signal when an Advice is invoked

The advice is not proxyable, so the signal is dispatched manually here.

AuthenticationProviderManager (TYPO3\Flow\Security\Authentication\AuthenticationProviderManager)

This class contains the following signals.

authenticatedToken

Autogenerated Proxy Method

loggedOut

Autogenerated Proxy Method

BeforeAdvice (TYPO3\Flow\Aop\Advice\BeforeAdvice)

This class contains the following signals.

adviceInvoked

Emits a signal when an Advice is invoked

The advice is not proxyable, so the signal is dispatched manually here.

Bootstrap (TYPO3\Flow\Core\Bootstrap)

This class contains the following signals.

finishedCompiletimeRun

Emits a signal that the compile run was finished.

finishedRuntimeRun

Emits a signal that the runtime run was finished.

bootstrapShuttingDown

Emits a signal that the bootstrap finished and is shutting down.

CacheCommandController (TYPO3\Flow\Command\CacheCommandController)

This class contains the following signals.

warmupCaches

Autogenerated Proxy Method

ConfigurationManager (TYPO3\Flow\Configuration\ConfigurationManager)

This class contains the following signals.

configurationManagerReady

Emits a signal after The ConfigurationManager has been loaded

CoreCommandController (TYPO3\Flow\Command\CoreCommandController)

This class contains the following signals.

finishedCompilationRun

Signals that the compile command was successfully finished.

Dispatcher (TYPO3\Flow\Mvc\Dispatcher)

This class contains the following signals.

beforeControllerInvocation

Autogenerated Proxy Method

afterControllerInvocation

Autogenerated Proxy Method

DoctrineCommandController (TYPO3\Flow\Command\DoctrineCommandController)

This class contains the following signals.

afterDatabaseMigration

Autogenerated Proxy Method

FileMonitor (TYPO3\Flow\Monitor\FileMonitor)

This class contains the following signals.

filesHaveChanged

Signalizes that the specified file has changed

directoriesHaveChanged

Signalizes that the specified directory has changed

PackageManager (TYPO3\Flow\Package\PackageManager)

This class contains the following signals.

packageStatesUpdated

Emits a signal when package states have been changed (e.g. when a package was created or activated)

The advice is not proxyable, so the signal is dispatched manually here.

PersistenceManager (TYPO3\Flow\Persistence\Doctrine\PersistenceManager)

This class contains the following signals.

allObjectsPersisted

Autogenerated Proxy Method

PersistenceManager (TYPO3\Flow\Persistence\Generic\PersistenceManager)

This class contains the following signals.

allObjectsPersisted

Autogenerated Proxy Method

PolicyService (TYPO3\Flow\Security\Policy\PolicyService)

This class contains the following signals.

configurationLoaded

Autogenerated Proxy Method

rolesInitialized

Autogenerated Proxy Method

SlaveRequestHandler (TYPO3\Flow\Cli\SlaveRequestHandler)

This class contains the following signals.

dispatchedCommandLineSlaveRequest

Emits a signal that a CLI slave request was dispatched.

Media Signals Reference

This reference was automatically generated from code on 2016-06-21

Asset (TYPO3\Media\Domain\Model\Asset)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

AssetService (TYPO3\Media\Domain\Service\AssetService)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

assetRemoved

Autogenerated Proxy Method

assetUpdated

Autogenerated Proxy Method

assetResourceReplaced

Autogenerated Proxy Method

Audio (TYPO3\Media\Domain\Model\Audio)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

Document (TYPO3\Media\Domain\Model\Document)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

Image (TYPO3\Media\Domain\Model\Image)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

ImageVariant (TYPO3\Media\Domain\Model\ImageVariant)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

Thumbnail (TYPO3\Media\Domain\Model\Thumbnail)

This class contains the following signals.

thumbnailCreated

Autogenerated Proxy Method

ThumbnailService (TYPO3\Media\Domain\Service\ThumbnailService)

This class contains the following signals.

thumbnailCreated

Autogenerated Proxy Method

Video (TYPO3\Media\Domain\Model\Video)

This class contains the following signals.

assetCreated

Autogenerated Proxy Method

Neos Signals Reference

This reference was automatically generated from code on 2016-06-07

ContentContext (TYPO3\Neos\Domain\Service\ContentContext)

This class contains the following signals.

beforeAdoptNode

Autogenerated Proxy Method

afterAdoptNode

Autogenerated Proxy Method

PublishingService (TYPO3\Neos\Service\PublishingService)

This class contains the following signals.

nodePublished

Autogenerated Proxy Method

nodeDiscarded

Autogenerated Proxy Method

Site (TYPO3\Neos\Domain\Model\Site)

This class contains the following signals.

siteChanged

Autogenerated Proxy Method

SiteImportService (TYPO3\Neos\Domain\Service\SiteImportService)

This class contains the following signals.

siteImported

Autogenerated Proxy Method

SiteService (TYPO3\Neos\Domain\Service\SiteService)

This class contains the following signals.

sitePruned

Autogenerated Proxy Method

UserService (TYPO3\Neos\Domain\Service\UserService)

This class contains the following signals.

userCreated

Autogenerated Proxy Method

userDeleted

Autogenerated Proxy Method

userUpdated

Autogenerated Proxy Method

rolesAdded

Autogenerated Proxy Method

rolesRemoved

Autogenerated Proxy Method

userActivated

Autogenerated Proxy Method

userDeactivated

Autogenerated Proxy Method

Content Repository Signals Reference

This reference was automatically generated from code on 2016-06-07

Context (TYPO3\TYPO3CR\Domain\Service\Context)

This class contains the following signals.

beforeAdoptNode

Autogenerated Proxy Method

afterAdoptNode

Autogenerated Proxy Method

Node (TYPO3\TYPO3CR\Domain\Model\Node)

This class contains the following signals.

beforeNodeMove

Autogenerated Proxy Method

afterNodeMove

Autogenerated Proxy Method

beforeNodeCopy

Autogenerated Proxy Method

afterNodeCopy

Autogenerated Proxy Method

beforeNodeCreate

Autogenerated Proxy Method

afterNodeCreate

Autogenerated Proxy Method

nodeAdded

Autogenerated Proxy Method

nodeUpdated

Autogenerated Proxy Method

nodeRemoved

Autogenerated Proxy Method

beforeNodePropertyChange

Autogenerated Proxy Method

nodePropertyChanged

Autogenerated Proxy Method

nodePathChanged

Autogenerated Proxy Method

NodeData (TYPO3\TYPO3CR\Domain\Model\NodeData)

This class contains the following signals.

nodePathChanged

Autogenerated Proxy Method

NodeDataRepository (TYPO3\TYPO3CR\Domain\Repository\NodeDataRepository)

This class contains the following signals.

repositoryObjectsPersisted

Autogenerated Proxy Method

PublishingService (TYPO3\TYPO3CR\Domain\Service\PublishingService)

This class contains the following signals.

nodePublished

Autogenerated Proxy Method

nodeDiscarded

Autogenerated Proxy Method

PublishingService (TYPO3\TYPO3CR\Service\PublishingService)

This class contains the following signals.

nodePublished

Autogenerated Proxy Method

nodeDiscarded

Autogenerated Proxy Method

Workspace (TYPO3\TYPO3CR\Domain\Model\Workspace)

This class contains the following signals.

baseWorkspaceChanged

Autogenerated Proxy Method

beforeNodePublishing

Autogenerated Proxy Method

afterNodePublishing

Autogenerated Proxy Method

Coding Guideline Reference

PHP Coding Guidelines & Best Practices

Coding Standards are an important factor for achieving a high code quality. A common visual style, naming conventions and other technical settings allow us to produce a homogenous code which is easy to read and maintain. However, not all important factors can be covered by rules and coding standards. Equally important is the style in which certain problems are solved programmatically - it’s the personality and experience of the individual developer which shines through and ultimately makes the difference between technically okay code or a well considered, mature solution.

These guidelines try to cover both, the technical standards as well as giving incentives for a common development style. These guidelines must be followed by everyone who creates code for the Flow core. Because Neos is based on Flow, it follows the same principles - therefore, whenever we mention Flow in the following sections, we equally refer to Neos. We hope that you feel encouraged to follow these guidelines as well when creating your own packages and Flow based applications.

CGL on One Page
The Coding Guidelines on One Page

The Coding Guidelines on One Page

The most important parts of our Coding Guidelines in a one page document you can print out and hang on your wall for easy reference. Does it get any easier than that?

Code Formatting and Layout aka “beautiful code”

The visual style of programming code is very important. In the Neos project we want many programmers to contribute, but in the same style. This will help us to:

  • Easily read/understand each others code and consequently easily spot security problems or optimization opportunities
  • It is a signal about consistency and cleanliness, which is a motivating factor for programmers striving for excellence

Some people may object to the visual guidelines since everyone has his own habits. You will have to overcome that in the case of Flow; the visual guidelines must be followed along with coding guidelines for security. We want all contributions to the project to be as similar in style and as secure as possible.

General considerations
  • Follow the PSR-2 standard for code formatting
  • Almost every PHP file in Flow contains exactly one class and does not output anything if it is called directly. Therefore you start your file with a <?php tag and must not end it with the closing ?>.
  • Every file must contain a header stating namespace and licensing information
    • Declare your namespace.
    • The copyright header itself must not start with /**, as this may confuse documentation generators!

The Flow standard file header:

<?php
namespace YourCompany\Package\Something\New;

/*
 * This file is part of the YourCompany.Package package.
 *
 * (c) YourCompany
 *
 * This package is Open Source Software. For the full copyright and license
 * information, please view the LICENSE file which was distributed with this
 * source code.
 */
  • Code lines are of arbitrary length, no strict limitations to 80 characters or something similar (wake up, graphical displays have been available for decades now…). But feel free to break lines for better readability if you think it makes sense!
  • Lines end with a newline a.k.a chr(10) - UNIX style
  • Files must be encoded in UTF-8 without byte order mark (BOM)

Make sure you use the correct license and mention the correct package in the header.

Indentation and line formatting

Since we adopted PSR-2 as coding standard we use spaces for indentation.

Here’s a code snippet which shows the correct usage of spaces.

Correct use of indentation:

/**
 * Returns the name of the currently set context.
 *
 * @return string Name of the current context
 */
public function getContextName()
{
    return $this->contextName;
}
Naming

Naming is a repeatedly undervalued factor in the art of software development. Although everybody seems to agree on that nice names are a nice thing to have, most developers choose cryptic abbreviations in the end (to save some typing). Beware that we Neos core developers are very passionate about naming (some people call it fanatic, well …). In our opinion spending 15 minutes (or more …) just to find a good name for a method is well spent time! There are zillions of reasons for using proper names and in the end they all lead to better readable, manageable, stable and secure code.

As a general note, english words (or abbreviations if necessary) must be used for all class names, method names, comments, variables names, database table and field names. The consensus is that english is much better to read for the most of us, compared to other languages.

When using abbreviations or acronyms remember to make them camel-cased as needed, no all-uppercase stuff. Admittedly there are a few places where we violate that rule willingly and for historical reasons.

Vendor namespaces

The base for namespaces as well as package keys is the vendor namespace. Since Flow is part of the Neos project, the core team decided to choose “Neos” as our vendor namespace. The Object Manager for example is known under the class name Neos\Flow\ObjectManagement\ObjectManager. In our examples you will find the Acme vendor namespace.

Why do we use vendor namespaces? This has two great benefits: first of all we don’t need a central package key registry and secondly, it allows anyone to seamlessly integrate third-party packages, such as Symfony2 components and Zend Framework components or virtually any other PHP library.

Think about your own vendor namespace for a few minutes. It will stay with you for a long time.

Package names

All package names start with an uppercase character and usually are written in UpperCamelCase. In order to avoid problems with different filesystems, only the characters a-z, A-Z, 0-9 and the dash sign “-” are allowed for package names – don’t use special characters.

The full package key is then built by combining the vendor namespace and the package, like Neos.Eel or Acme.Demo.

Namespace and Class names
  • Only the characters a-z, A-Z and 0-9 are allowed for namespace and class names.
  • Namespaces are usually written in UpperCamelCase but variations are allowed for well established names and abbreviations.
  • Class names are always written in UpperCamelCase.
  • The unqualified class name must be meant literally even without the namespace.
  • The main purpose of namespaces is categorization and ordering
  • Class names must be nouns, never adjectives.
  • The name of abstract classes must start with the word “Abstract”, class names of aspects must end with the word “Aspect”.

Incorrect naming of namespaces and classes

Fully qualified class name Unqualified name Remarks
\Neos\Flow\Session\Php Php The class is not a representation of PHP
\Neos\Cache\Backend\File File The class doesn’t represent a file!
\Neos\Flow\Session\Interface Interface Not allowed, “Interface” is a reserved keyword
\Neos\Foo\Controller\Default Default Not allowed, “Default” is a reserved keyword
\Neos\Flow\Objects\Manager Manager Just “Manager” is too fuzzy

Correct naming of namespaces and classes

Fully qualified class name Unqualified name Remarks
\Neos\Flow\Session\PhpSession PhpSession That’s a PHP Session
\Neos\Flow\Cache\Backend\FileBackend FileBackend A File Backend
\Neos\Flow\Session\SessionInterface SessionInterface Interface for a session
\Neos\Foo\Controller\StandardController StandardController The standard controller
\Neos\Flow\Objects\ObjectManager ObjectManager “ObjectManager” is clearer

Edge cases in naming of namespaces and classes

Fully qualified class name Unqualified name Remarks
\Neos\Flow\Mvc\ControllerInterface ControllerInterface Consequently the interface belongs to all the controllers in the Controller sub namespace
\Neos\Flow\Mvc\Controller\ControllerInterface   Better
\Neos\Cache\AbstractBackend AbstractBackend Same here: In reality this class belongs to the backends
\Neos\Cache\Backend\AbstractBackend   Better

Note

When specifying class names to PHP, always reference the global namespace inside namespaced code by using a leading backslash. When referencing a class name inside a string (e.g. given to the get-Method of the ObjectManager, in pointcut expressions or in YAML files), never use a leading backslash. This follows the native PHP notion of names in strings always being seen as fully qualified.

Importing Namespaces

If you refer to other classes or interfaces you are encouraged to import the namespace with the use statement if it improves readability.

Following rules apply:

  • If importing namespaces creates conflicting class names you might alias class/interface or namespaces with the as keyword.
  • One use statement per line, one use statement for each imported namespace
  • Imported namespaces should be ordered alphabetically (modern IDEs provide support for this)

Tip

use statements have no side-effects (e.g. they don’t trigger autoloading). Nevertheless you should remove unused imports for better readability

Interface names

Only the characters a-z, A-Z and 0-9 are allowed for interface names – don’t use special characters.

All interface names are written in UpperCamelCase. Interface names must be adjectives or nouns and have the Interface suffix. A few examples follow:

  • \Neos\Flow\ObjectManagement\ObjectInterface
  • \Neos\Flow\ObjectManagement\ObjectManagerInterface
  • \MyCompany\MyPackage\MyObject\MySubObjectInterface
  • \MyCompany\MyPackage\MyObject\MyHtmlParserInterface
Exception names

Exception naming basically follows the rules for naming classes. There are two possible types of exceptions: generic exceptions and specific exceptions. Generic exceptions should be named “Exception” preceded by their namespace. Specific exceptions should reside in their own sub-namespace end with the word Exception.

  • \Neos\Flow\ObjectManagement\Exception
  • \Neos\Flow\ObjectManagement\Exception\InvalidClassNameException
  • \MyCompany\MyPackage\MyObject\Exception
  • \MyCompany\MyPackage\MyObject\Exception\OutOfCoffeeException
On consistent naming of classes, interfaces and friends

At times, the question comes up, why we use a naming scheme that is inconsistent with what we write in the PHP sources. Here is the best explanation we have:

At first glance this feels oddly inconsistent; We do, after all, put each of those at the same position within php code.

But, I think leaving Abstract as a prefix, and Interface/Trait as suffixes makes sense. Consider the opposite of how we do it: “Interface Foo”, “Trait Foo” both feel slightly odd when I say them out loud, and “Foo Abstract” feels very wrong. I think that is because of the odd rules of grammar in English (Oh! English. What an ugly inconsistent language! And yet, it is my native tongue).

Consider the phrase “the poor man”. ‘poor’ is an adjective that describes ‘man’, a noun. Poor happens to also work as a noun, but the definition changes slightly when you use it as a noun instead of an adjective. And, if you were to flip the phrase around, it would not make much sense, or could have (sometimes funny) alternative meanings: “the man poor” (Would that mean someone without a boyfriend?)

The word “Abstract” works quite well as an adjective, but has the wrong meaning as a noun. An “Abstract” (noun) is “an abridgement or summary” or a kind of legal document, or any other summary-like document. But we’re not talking about a document, we’re talking about the computing definition which is an adjective: “abstract type”. ( http://en.wiktionary.org/wiki/abstract)

“Abstract” can be a noun, an adjective, or a verb. But, we want the adjective form. “Interface” is a noun or a verb. “Trait” is always a noun. So, based on current English rules, “Abstract Foo”, “Foo Interface” and “Foo Trait” feel the most natural. English is a living language where words can move from one part of speech to another, so we could get away with using the words in different places in the sentence. But that would, at least to begin with, feel awkward.

So, I blame the inconsistent placement of Abstract, Interface, and Trait on the English language.

[…]

—Jacob Floyd, http://lists.typo3.org/pipermail/flow/2014-November/005625.html

Method names

All method names are written in lowerCamelCase. In order to avoid problems with different filesystems, only the characters a-z, A-Z and 0-9 are allowed for method names – don’t use special characters.

Make method names descriptive, but keep them concise at the same time. Constructors must always be called __construct(), never use the class name as a method name.

  • myMethod()
  • someNiceMethodName()
  • betterWriteLongMethodNamesThanNamesNobodyUnderstands()
  • singYmcaLoudly()
  • __construct()
Variable names

Variable names are written in lowerCamelCase and should be

  • self-explanatory
  • not shortened beyond recognition, but rather longer if it makes their meaning clearer

The following example shows two variables with the same meaning but different naming. You’ll surely agree the longer versions are better (don’t you …?).

Correct naming of variables

  • $singletonObjectsRegistry
  • $argumentsArray
  • $aLotOfHtmlCode

Incorrect naming of variables

  • $sObjRgstry
  • $argArr
  • $cx

As a special exception you may use variable names like $i, $j and $k for numeric indexes in for loops if it’s clear what they mean on the first sight. But even then you should want to avoid them.

Constant names

All constant names are written in UPPERCASE. This includes TRUE, FALSE and NULL. Words can be separated by underscores - you can also use the underscore to group constants thematically:

  • STUFF_LEVEL
  • COOLNESS_FACTOR
  • PATTERN_MATCH_EMAILADDRESS
  • PATTERN_MATCH_VALIDHTMLTAGS

It is, by the way, a good idea to use constants for defining regular expression patterns (as seen above) instead of defining them somewhere in your code.

Filenames

These are the rules for naming files:

  • All filenames are UpperCamelCase.
  • Class and interface files are named according to the class or interface they represent
  • Each file must contain only one class or interface
  • Names of files containing code for unit tests must be the same as the class which is tested, appended with “Test.php”.
  • Files are placed in a directory structure representing the namespace structure. You may use PSR-0 or PSR-4 autoloading as you like. We generally use PSR-4.

File naming in Flow

Neos.TemplateEngine/Classes/TemplateEngineInterface.php
Contains the interface \Neos\TemplateEngine\TemplateEngineInterface which is part of the package Neos.TemplateEngine
Neos.Flow/Classes/Error/RuntimeException.php
Contains the \Neos\Flow\Error\Messages\RuntimeException being a part of the package Neos.Flow
Acme.DataAccess/Classes/CustomQuery.php
Contains class \Acme\DataAccess\CustomQuery which is part of the package Acme.DataAccess
Neos.Flow/Tests/Unit/Package/PackageManagerTest.php
Contains the class \Neos\Flow\Tests\Unit\Package\PackageManagerTest which is a PHPUnit testcase for Package\PackageManager.
PHP code formatting
PSR-2

We follow the PSR-2 standard which is defined by PHP FIG. You should read the full PSR-2 standard. .. psr-2 standard: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md

Some things are not specified in PSR-2, so here are some amendments.

Strings

In general, we use single quotes to enclose literal strings:

$neos = 'A great project from a great team';

If you’d like to insert values from variables, concatenate strings. A space must be inserted before and after the dot for better readability:

$message = 'Hey ' . $name . ', you look ' . $appearance . ' today!';

You may break a string into multiple lines if you use the dot operator. You’ll have to indent each following line to mark them as part of the value assignment:

$neos = 'A great ' .
  'project from ' .
  'a great ' .
  'team';

You should also consider using a PHP function such as sprintf() to concatenate strings to increase readability:

$message = sprintf('Hey %s, you look %s today!', $name, $appearance);
Development Process
Test-Driven Development

In a nutshell: before coding a feature or fixing a bug, write an unit test.

Whatever you do: before committing changes to the repository, run all unit tests to make sure nothing is broken!

Commit Messages

To have a clear and focused history of code changes is greatly helped by using a consistent way of writing commit messages. Because of this and to help with (partly) automated generation of change logs for each release we have defined a fixed syntax for commit messages that is to be used.

Tip

Never commit without a commit message explaining the commit!

The syntax is as follows:

  • Start with one of the following codes:

    FEATURE:

    A feature change. Most likely it will be an added feature, but it could also be removed. For additions there should be a corresponding ticket in the issue tracker.

    BUGFIX:

    A fix for a bug. There should be a ticket corresponding to this in the issue tracker as well as a new) unit test for the fix.

    SECURITY:

    A security related change. Those must only be committed by active contributors in agreement with the security team.

    TASK:

    Anything not covered by the above categories, e.g. coding style cleanup or documentation changes. Usually only used if there’s no corresponding ticket.

    Except for SECURITY each of the above codes can be prefixed with WIP to mark a change work in progress. This means that it is not yet ready for a final review. The WIP prefix must be removed before a change is merged.

  • The code is followed by a short summary in the same line, no full stop at the end. If the change affects the public API or is likely to break things on the user side, start the line with [!!!]. This indicates a breaking change that needs human action when updating. Make sure to explain why a change is breaking and in what circumstances.

  • Then follows (after a blank line) a custom message explaining what was done. It should be written in a style that serves well for a change log read by users.

  • If there is more to say about a change add a new paragraph with background information below. In case of breaking changes give a hint on what needs to be changed by the user.

  • If corresponding tickets exist, mention the ticket number(s) using footer lines after another blank line and use the following actions:

    Fixes <Issue-Id>

    If the change fixes a bug, resolves a feature request or task.

    Related to <Issue-Id>

    If the change relates to an issue but does not resolve or fix it.

A commit messages following the rules…:

TASK: Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary.  Wrap it to about 72
characters or so.  In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body.  The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.

Write your commit message in the present tense: "Fix bug" and not "Fixed
bug."  This convention matches up with commit messages generated by
commands like git merge and git revert.

Code snippets::

 should be written in
 ReStructuredText compatible
 format for better highlighting

Further paragraphs come after blank lines.

* Bullet points are okay, too
* An asterisk is used for the bullet, it can be preceded by a single
  space. This format is rendered correctly by Forge (redmine)
* Use a hanging indent

Fixes #123

Examples of good and bad subject lines:

Introduce xyz service                               // BAD, missing code prefix
BUGFIX: Fixed bug xyz                               // BAD, subject should be written in present tense
WIP !!! TASK: A breaking change                     // BAD, subject has to start with [!!!] for breaking changes
BUGFIX: Make SessionManager remove expired sessions // GOOD, the line explains what the change does, not what the
                                                       bug is about (this should be explained in the following lines
                                                       and in the related bug tracker ticket)
Source Code Documentation

All code must be documented with inline comments. The syntax is similar to that known from the Java programming language (JavaDoc). This way code documentation can automatically be generated.

Documentation Blocks

A file contains different documentation blocks, relating to the class in the file and the members of the class. A documentation block is always used for the entity it precedes.

Class documentation

Classes have their own documentation block describing the classes purpose.

Standard documentation block:

/**
 * First sentence is short description. Then you can write more, just as you like
 *
 * Here may follow some detailed description about what the class is for.
 *
 * Paragraphs are separated by an empty line.
 */
class SomeClass {
 ...
}

Additional tags or annotations, such as @see or @Flow\Aspect, can be added as needed.

Documenting variables, constants, includes

Properties of a class should be documented as well. We use the short version for documenting them.

Standard variable documentation block:

/**
 * A short description, very much recommended
 *
 * @var string
 */
protected $title = 'Untitled';

In general you should try to code in a way that the types can be derived (e.g. by using type hints and annotations). In some cases this is not possible, for example when iterating through an array of objects. In these cases it’s ok to add inline @var annotations to increase readability and to activate auto-completion and syntax-highlighting:

protected function someMethod(array $products) {
   /** @var $product \Acme\SomePackage\Domain\Model\Product */
   foreach ($products as $product) {
       $product->getTitle();
   }
}
Method documentation

For a method, at least all parameters and the return value must be documented.

Standard method documentation block:

/**
 * A description for this method
 *
 * Paragraphs are separated by an empty line.
 *
 * @param \Neos\Blog\Domain\Model\Post $post A post
 * @param string $someString This parameter should contain some string
 * @return void
 */
public function addStringToPost(\Neos\Blog\Domain\Model\Post $post, $someString) {
 ...
}

A special note about the @param tags: The parameter type and name are separated by one space, not aligned. Do not put a colon after the parameter name. Always document the return type, even if it is void - that way it is clearly visible it hasn’t just been forgotten (only constructors never have a @return annotation!).

Testcase documentation

Testcases need to be marked as being a test and can have some more annotations.

Standard testcase documentation block:

/**
 * @test
 */
public function fooReturnsBarForQuux() {
 ...
}
Defining the Public API

Not all methods with a public visibility are necessarily part of the intended public API of a project. For Flow, only the methods explicitly defined as part of the public API will be kept stable and are intended for use by developers using Flow. Also the API documentation we produce will only cover the public API.

To mark a method as part of the public API, include an @api annotation for it in the docblock.

Defining the public API:

/**
 * This method is part of the public API.
 *
 * @return void
 * @api
 */
public function fooBar() {
 ...
}

Tip

When something in a class or an interface is annotated with @api make sure to also annotate the class or interface itself! Otherwise it will be ignored completely when official API documentation is rendered!

Overview of Documentation Annotations

There are not only documentation annotations that can be used. In Flow annotations are also used in the MVC component, for defining aspects and advices for the AOP framework as well as for giving instructions to the Persistence framework. See the individual chapters for information on their purpose and use.

Here is a list of annotations used within the project. They are grouped by use case and the order given here should be kept for the sake of consistency.

Interface Documentation

  • @api
  • @since
  • @deprecated

Class Documentation

  • @FlowIntroduce
  • @FlowEntity
  • @FlowValueObject
  • @FlowScope
  • @FlowAutowiring
  • @FlowLazy
  • @FlowAspect
  • @api
  • @since
  • @deprecated

Property Documentation

  • @FlowIntroduce
  • @FlowIdentity
  • @FlowTransient
  • @FlowLazy
  • @FlowIgnoreValidation
  • @FlowInject
  • @FlowInjectConfiguration
  • @FlowValidate
  • @var
  • @api
  • @since
  • @deprecated

Constructor Documentation

  • @param
  • @throws
  • @api
  • @since
  • @deprecated

Method Documentation

  • @FlowAfter
  • @FlowAfterReturning
  • @FlowAfterThrowing
  • @FlowAround
  • @FlowBefore
  • @FlowPointcut
  • @FlowAutowiring
  • @FlowCompileStatic
  • @FlowFlushesCaches
  • @FlowInternal
  • @FlowSession
  • @FlowSignal
  • @FlowIgnoreValidation
  • @FlowSkipCsrfProtection
  • @FlowValidate
  • @FlowValidationGroups
  • @param
  • @return
  • @throws
  • @api
  • @since
  • @deprecated

Testcase Documentation

  • @test
  • @dataProvider
  • @expectedException

Tip

Additional annotations (more or less only the @todo and @see come to mind here), should be placed after all other annotations.

Best Practices
Flow

This section gives you an overview of Flow’s coding rules and best practices.

Error Handling and Exceptions

Flow makes use of a hierarchy for its exception classes. The general rule is to throw preferably specific exceptions and usually let them bubble up until a place where more general exceptions are caught. Consider the following example:

Some method tried to retrieve an object from the object manager. However, instead of providing a string containing the object name, the method passed an object (of course not on purpose - something went wrong). The object manager now throws an InvalidObjectName exception. In order to catch this exception you can, of course, catch it specifically - or only consider a more general Object exception (or an even more general Flow exception). This all works because we have the following hierarchy:

+ \Neos\Flow\Exception
+ \Neos\Flow\ObjectManagement\Exception
+ \Neos\Flow\ObjectManagement\Exception\InvalidObjectNameException
Throwing an exception

When throwing an exception, make sure to provide a clear error message and an error code being the unix timestamp of when you write the ``throw`` statement. That error code must be unique, so watch out when doing copy and paste!

Unit Testing

Some notes for a start:

  • Never use the object manager or factory in unit tests! If they are needed, mock them.
  • Avoid tests for the scope of an object. Those tests test the object factory, rather then the test target. Such a test should be done by checking for the presence of an expected @scope annotation – eventually we will find an elegant way for this.
Cross Platform Coding
  • When concatenating paths, always use \Neos\Utility\Files::concatenatePaths() to avoid trouble.
PHP in General
  • All code should be object oriented. This means there should be no functions outside classes if not absolutely necessary. If you need a “container” for some helper methods, consider creating a static class.

  • All code must make use of PHP5 advanced features for object oriented programming.

    • Use PHP namespaces
    • Always declare the scope (public, protected, private) of methods and member variables
    • Make use of iterators and exceptions, have a look at the SPL
  • Make use of type-hinting wherever possible

  • Always use <?php as opening tags (never only <?)

  • Never use the closing tag ?> at the end of a file, leave it out

  • Never use the shut-up operator @ to suppress error messages. It makes debugging harder, is dirty style and slow as hell

  • Prefer strict comparisons whenever possible, to avoid problems with truthy and falsy values that might behave different than what you expect. Here are some examples:

    Examples of good and bad comparisons:

    if ($template)             // BAD
    if (isset($template))      // GOOD
    if ($template !== NULL))   // GOOD
    if ($template !== ''))     // GOOD
    
    if (strlen($template) > 0) // BAD! strlen("-1") is greater than 0
    if (is_string($template) && strlen($template) > 0) // BETTER
    
    if ($foo == $bar)          // BAD, avoid truthy comparisons
    if ($foo != $bar)          // BAD, avoid falsy comparisons
    if ($foo === $bar))        // GOOD
    if ($foo !== $bar))        // GOOD
    
    Truthy and falsy are fuzzy...

    Truthy and falsy are fuzzy…

  • Order of methods in classes. To gain a better overview, it helps if methods in classes are always ordered in a certain way. We prefer the following:

    • constructor
    • injection methods
    • initialization methods (including initializeObject())
    • public methods
    • protected methods
    • private methods
    • shutdown methods
    • destructor
  • Avoid double-negation. Instead of exportSystemView(..., $noRecurse) use exportSystemView(..., $recurse). It is more logical to pass TRUE if you want recursion instead of having to pass FALSE. In general, parameters negating things are a bad idea.

Comments

In general, comments are a good thing and we strive for creating a well-documented source code. However, inline comments can often be a sign for a bad code structure or method naming. [1] As an example, consider the example for a coding smell:

 // We only allow valid persons
if (is_object($p) && strlen($p->lastN) > 0 && $p->hidden === FALSE && $this->environment->moonPhase === MOON_LIB::CRESCENT) {
 $xmM = $thd;
}

This is a perfect case for the refactoring technique “extract method”: In order to avoid the comment, create a new method which is as explanatory as the comment:

if ($this->isValidPerson($person) {
  $xmM = $thd;
}

Bottom line is: You may (and are encouraged to) use inline comments if they support the readability of your code. But always be aware of possible design flaws you probably try to hide with them.


[1]This is also referred to as a bad “smell” in the theory of Refactoring. We highly recommend reading “Refactoring” by Martin Fowler - if you didn’t already.

JavaScript Coding Guidelines

Here, you will find an explanation of the JavaScript Coding Guidelines we use. Generally, we strive to follow the TYPO3 Flow Coding Guidelines as closely as possible, with exceptions which make sense in the JavaScript context.

This guideline explains mostly how we want JavaScript code to be formatted; and it does not deal with the Neos User Interface structure. If you want to know more about the Neos User Interface architecture, have a look into the “Neos User Interface Development” book.

Naming Conventions
  • one class per file, with the same naming convention as TYPO3 Flow.

  • This means all classes are built like this: <PackageKey>.<SubNamespace>.<ClassName>, and this class is implemented in a JavaScript file located at <Package>/.../JavaScript/<SubNamespace>/<ClassName>.js

  • Right now, the base directory for JavaScript in TYPO3 Flow packages Resources/Public/JavaScript, but this might still change.

  • We suggest that the base directory for JavaScript files is JavaScript.

  • Files have to be encoded in UTF-8 without byte order mark (BOM).

  • Classes and namespaces are written in UpperCamelCase, while properties and methods are written in lowerCamelCase.

  • The xtype of a class is always the fully qualified class name. Every class which can be instantiated needs to have an xtype declaration.

  • Never create a class which has classes inside itself. Example: if the class TYPO3.Foo exists, it is prohibited to create a class TYPO3.Foo.Bar.You can easily check this: If a directory with the same name as the JavaScript file exists, this is prohibited.

    Here follows an example:

    TYPO3.Foo.Bar // implemented in .../Foo/Bar.js
    TYPO3.Foo.Bar = ...
    
    TYPO3.Foo // implemented in ...Foo.js
    TYPO3.Foo = ..... **overriding the "Bar" class**
    

    So, if the class TYPO3.Foo.Bar is included before TYPO3.Foo, then the second class definition completely overrides the Bar object. In order to prevent such issues, this constellation is forbidden.

  • Every class, method and class property should have a doc comment.

  • Private methods and properties should start with an underscore (_) and have a @private annotation.

Doc Comments

Generally, doc comments follow the following form:

/**
 *
 */

See the sections below on which doc comments are available for the different elements (classes, methods, …).

We are using http://code.google.com/p/ext-doc/ for rendering an API documentation from the code, that’s why types inside @param, @type and @cfg have to be written in braces like this:

@param {String} theFirstParameter A Description of the first parameter
@param {My.Class.Name} theSecondParameter A description of the second parameter

Generally, we do not use @api annotations, as private methods and attributes are marked with @private and prefixed with an underscore. So, everything which is not marked as private belongs to the public API!

We are not sure yet if we should use @author annotations at all. (TODO Decide!)

To make a reference to another method of a class, use the {@link #methodOne This is an example link to method one} syntax.

If you want to do multi-line doc comments, you need to format them with <br>, <pre> and other HTML tags:

/**
 * Description of the class. Make it as long as needed,
 * feel free to explain how to use it.
 * This is a sample class <br/>
 * The file encoding should be utf-8 <br/>
 * UTF-8 Check: öäüß <br/>
 * {@link #methodOne This is an example link to method one}
 */
Class Definitions

Classes can be declared singleton or prototype. A class is singleton, if only one instance of this class will exist at any given time. An class is of type prototype, if more than one object can be created from the class at run-time. Most classes will be of type prototype.

You will find examples for both below.

Prototype Class Definitions

Example of a prototype class definition:

Ext.ns("TYPO3.TYPO3.Content");


/*
 * This file is part of the TYPO3.Neos package.
 *
 * (c) Contributors of the Neos Project - www.neos.io
 *
 * This package is Open Source Software. For the full copyright and license
 * information, please view the LICENSE file which was distributed with this
 * source code.
 */

/**
 * @class TYPO3.TYPO3.Content.FrontendEditor
 *
 * The main frontend editor.
 *
 * @namespace TYPO3.TYPO3.Content
 * @extends Ext.Container
 */
TYPO3.TYPO3.Content.FrontendEditor = Ext.extend(Ext.Container, {
        // here comes the class contents
});
Ext.reg('TYPO3.TYPO3.Content.FrontendEditor', TYPO3.TYPO3.Content.FrontendEditor);
  • At the very beginning of the file is the namespace declaration of the class, followed by a newline.
  • Then follows the class documentation block, which must start with the @class declaration in the first line.
  • Now comes a description of the class, possibly with examples.
  • Afterwards must follow the namespace of the class and the information about object extension
  • Now comes the actual class definition, using Ext.extend.
  • As the last line of the class, it follows the xType registration. We always use the fully qualified class name as xtype

Usually, the constructor of the class receives a hash of parameters. The possible configuration options need to be documented inside the class with the @cfg annotation:

TYPO3.TYPO3.Content.FrontendEditor = Ext.extend(Ext.Container, {
        /**
         * An explanation of the configuration option followed
         * by a blank line.
         *
         * @cfg {Number} configTwo
         */
        configTwo: 10
        ...
}
Singleton Class Definitions

Now comes a singleton class definition. You will see that it is very similar to a prototype class definition, we will only highlight the differences.

Example of a singleton class definition:

Ext.ns("TYPO3.TYPO3.Core");


/*
 * This file is part of the TYPO3.Neos package.
 *
 * (c) Contributors of the Neos Project - www.neos.io
 *
 * This package is Open Source Software. For the full copyright and license
 * information, please view the LICENSE file which was distributed with this
 * source code.
 */

/**
 * @class TYPO3.TYPO3.Core.Application
 *
 * The main entry point which controls the lifecycle of the application.
 *
 * @namespace TYPO3.TYPO3.Core
 * @extends Ext.util.Observable
 * @singleton
 */
TYPO3.TYPO3.Core.Application = Ext.apply(new Ext.util.Observable, {
        // here comes the class contents
});
  • You should add a @singleton annotation to the class doc comment after the @namespace and @extends annotation
  • In singleton classes, you use Ext.apply. Note that you need to use new to instantiate the base class.
  • There is no xType registration in singletons, as they are available globally anyhow.
Class Doc Comments

Class Doc Comments should always be in the following order:

  • @class <Name.Of.Class> (required)
  • Then follows a description of the class, which can span multiple lines. Before and after this description should be a blank line.
  • @namespace <Name.Of.Namespace> (required)
  • @extends <Name.Of.BaseClass> (required)
  • @singleton (required if the class is a singleton)

If the class has a non-empty constructor, the following doc comments need to be added as well, after a blank line:

  • @constructor
  • @param {<type>} <nameOfParameter> <description of parameter> for every parameter of the constructor

Example of a class doc comment without constructor:

/**
 * @class Acme.Foo.Bar
 *
 * Some Description of the class,
 * which can possibly span multiple lines
 *
 * @namespace Acme.Foo
 * @extends TYPO3.TYPO3.Core.SomeOtherClass
 */

Example of a class doc comment with constructor:

/**
 * @class Acme.TYPO3.Foo.ClassWithConstructor
 *
 * This class has a constructor!
 *
 * @namespace Acme.TYPO3.Foo
 * @extends TYPO3.TYPO3.Core.SomeOtherClass
 *
 * @constructor
 * @param {String} id The ID which to use
 */
Method Definitions

Methods should be documented the following way, with a blank line between methods.

Example of a method comment:

...
TYPO3.TYPO3.Core.Application = Ext.apply(new Ext.util.Observable, {
        ... property definitions ...
        /**
         * This is a method declaration; and the
         * explanatory text is followed by a newline.
         *
         * @param {String} param1 Parameter name
         * @param {String} param2 (Optional) Optional parameter
         * @return {Boolean} Return value
         */
        aPublicMethod: function(param1, param2) {
                return true;
        },

        /**
         * this is a private method of this class,
         * the private annotation marks them an prevent that they
         * are listed in the api doc. As they are private, they
         * have to start with an underscore as well.
         *
         * @return {void}
         * @private
         */
        _sampleMethod: function() {
        }
}
...

Contrary to what is defined in the TYPO3 Flow PHP Coding Guidelines, methods which are public automatically belong to the public API, without an @api annotation. Contrary, methods which do not belong to the public API need to begin with an underscore and have the @private annotation.

  • All methods need to have JSDoc annotations.
  • Every method needs to have a @return annotation. In case the method does not return anything, a @return {void} is needed, otherwise the concrete return value should be described.
Property Definitions

All properties of a class need to be properly documented as well, with an @type annotation. If a property is private, it should start with an underscore and have the @private annotation at the last line of its doc comment:

...
TYPO3.TYPO3.Core.Application = Ext.apply(new Ext.util.Observable, { // this is just an example class definition
        /**
         * Explanation of the property
         * which is followed by a newline
         *
         * @type {String}
         */
        propertyOne: 'Hello',

        /**
         * Now follows a private property
         * which starts with an underscore.
         *
         * @type {Number}
         * @private
         */
        _thePrivateProperty: null,
        ...
}
Code Style
  • use single quotes(‘) instead of double quotes(“) for string quoting

  • Multi-line strings (using \) are forbidden. Instead, multi-line strings should be written like this:

    'Some String' +
    ' which spans' +
    ' multiple lines'
    
  • There is no limitation on line length.

  • JavaScript constants (true, false, null) must be written in lowercase, and not uppercase.

  • Custom JavaScript constants should be avoided.

  • Use a single var statement at the top of a method to declare all variables:

    function() {
            var myVariable1, myVariable2, someText;
            // now, use myVariable1, ....
    }
    
    Please do **not assign** values to the variables in the initialization, except empty
    default values::
    
    // DO:
    function() {
            var myVariable1, myVariable2;
            ...
    }
    // DO:
    function() {
            var myVariable1 = {}, myVariable2 = [], myVariable3;
            ...
    }
    // DON'T
    function() {
            var variable1 = 'Hello',
                    variable2 = variable1 + ' World';
            ...
    }
    
  • We use a single TAB for indentation.

  • Use inline comments sparingly, they are often a hint that a new method must be introduced.

    Inline Comments must be indented one level deeper than the current nesting level:

    function() {
            var foo;
                    // Explain what we are doing here.
            foo = '123';
    }
    
  • Whitespace around control structures like if, else, … should be inserted like in the TYPO3 Flow CGLs:

    if (myExpression) {
            // if part
    } else {
            // Else Part
    }
    
  • Arrays and Objects should never have a trailing comma after their last element

  • Arrays and objects should be formatted in the following way:

    [
            {
                    foo: 'bar'
            }, {
                    x: y
            }
    ]
    
  • Method calls should be formatted the following way:

    // for simple parameters:
    new Ext.blah(options, scope, foo);
    object.myMethod(foo, bar, baz);
    
    // when the method takes a **single** parameter of type **object** as argument, and this object is specified directly in place:
    new Ext.Panel({
            a: 'b',
            c: 'd'
    });
    
    // when the method takes more parameters, and one is a configuration object which is specified in place:
    new Ext.blah(
            {
                    foo: 'bar'
            },
            scope,
            options
    );<
    

TODO: are there JS Code Formatters / Indenters, maybe the Spket JS Code Formatter?

Using JSLint to validate your JavaScript

JSLint is a JavaScript program that looks for problems in JavaScript programs. It is a code quality tool. When C was a young programming language, there were several common programming errors that were not caught by the primitive compilers, so an accessory program called lint was developed that would scan a source file, looking for problems. jslint is the same for JavaScript.

JavaScript code ca be validated on-line at http://www.jslint.com/. When validating the JavaScript code, “The Good Parts” family options should be set. For that purpose, there is a button “The Good Parts” to be clicked.

Instead of using it online, you can also use JSLint locally, which is now described. For the sake of convenience, the small tutorial bellow demonstrates how to use JSlint with the help of CLI wrapper to enable recursive validation among directories which streamlines the validation process.

  • Download Rhino from http://www.mozilla.org/rhino/download.html and put it for instance into /Users/john/WebTools/Rhino

  • Download JSLint.js (@see attachment “jslint.js”, line 5667-5669 contains the configuration we would like to have, still to decide) (TODO)

  • Download jslint.php (@see attachment “jslint.php” TODO), for example into /Users/fudriot/WebTools/JSLint

  • Open and edit path in jslint.php -> check variable $rhinoPath and $jslintPath

  • Add an alias to make it more convenient in the terminal:

    alias jslint '/Users/fudriot/WebTools/JSLint/jslint.php'
    

Now, you can use JSLint locally:

// scan one file or multi-files
jslint file.js
jslint file-1.js file-2.js

// scan one directory or multi-directory
jslint directory
jslint directory-1 directory-2

// scan current directory
jslint .

It is also possible to adjust the validation rules JSLint uses. At the end of file jslint.js, it is possible to customize the rules to be checked by JSlint by changing options’ value. By default, the options are taken over the book “JavaScript: The Good Parts” which is written by the same author of JSlint.

Below are the options we use for TYPO3 v5:

bitwise: true, eqeqeq: true, immed: true,newcap: true, nomen: false,
onevar: true, plusplus: false, regexp: true, rhino: true, undef: false,
white: false, strict: true

In case some files needs to be evaluated with special rules, it is possible to add a comment on the top of file which can override the default ones:

/* jslint white: true, evil: true, laxbreak: true, onevar: true, undef: true,
nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true,
newcap: true, immed: true */

More information about the meaning and the reasons of the rules can be found at http://www.jslint.com/lint.html

Event Handling

When registering an event handler, always use explicit functions instead of inline functions to allow overriding of the event handler.

Additionally, this function needs to be prefixed with on to mark it as event handler function. Below follows an example for good and bad code.

Good Event Handler Code:

TYPO3.TYPO3.Application.on('theEventName', this._onCustomEvent, this);

Bad Event Handler Code:

TYPO3.TYPO3.Application.on(
        'theEventName',
        function() {
                alert('Text');
        },
        this
);

All events need to be explicitly documented inside the class where they are fired onto with an @event annotation:

TYPO3.TYPO3.Core.Application = Ext.apply(new Ext.util.Observable, {
        /**
         * @event eventOne Event declaration
         */

        /**
         * @event eventTwo Event with parameters
         * @param {String} param1 Parameter name
         * @param {Object} param2 Parameter name
         * <ul>
         * <li><b>property1:</b> description of property1</li>
         * <li><b>property2:</b> description of property2</li>
         * </ul>
         */
        ...
}

Additionally, make sure to document if the scope of the event handler is not set to this, i.e. does not point to its class, as the user expects this.

ExtJS specific things

TODO

  • explain initializeObject
  • how to extend Ext components
  • can be extended by using constructor() not initComponents() like it is for panels and so on
How to extend data stores

This is an example for how to extend an ExtJS data store:

TYPO3.TYPO3.Content.DummyStore = Ext.extend(Ext.data.Store, {

        constructor: function(cfg) {
                cfg = cfg || {};
                var config = Ext.apply(
                        {
                                autoLoad: true
                        },
                        cfg
                );

                TYPO3.TYPO3.Content.DummyStore.superclass.constructor.call(
                        this,
                        config
                );
        }
});
Ext.reg('TYPO3.TYPO3.Content.DummyStore', TYPO3.TYPO3.Content.DummyStore);
Unit Testing
  • It’s highly recommended to write unit tests for javascript classes. Unit tests should be located in the following location: Package/Tests/JavaScript/...
  • The structure below this folder should reflect the structure below Package/Resources/Public/JavaScript/... if possible.
  • The namespace for the Unit test classes is Package.Tests.
  • TODO: Add some more information about Unit Testing for JS
  • TODO: Add note about the testrunner when it’s added to the package
  • TODO: http://developer.yahoo.com/yui/3/test/

Node Migration Reference

Node migrations can be used to deal with renamed node types and property names, set missing default values for properties, adjust content dimensions and more.

Node migrations work by applying transformations on nodes. The nodes that will be transformed are selected through filters in migration files.

The Content Repository comes with a number of common transformations:

  • AddDimensions
  • AddNewProperty
  • ChangeNodeType
  • ChangePropertyValue
  • RemoveNode
  • RemoveProperty
  • RenameDimension
  • RenameNode
  • RenameProperty
  • SetDimensions
  • StripTagsOnProperty

They all implement the TYPO3\TYPO3CR\Migration\Transformations\TransformationInterface. Custom transformations can be developed against that interface as well, just use the fully qualified class name for those when specifying which transformation to use.

Migration files

To use node migrations to adjust a setup to changed configuration, a YAML file is created that configures the migration by setting up filters to select what nodes are being worked on by transformations. The Content Repository comes with a number of filters:

  • DimensionValues
  • IsRemoved
  • NodeName
  • NodeType
  • PropertyNotEmpty
  • Workspace

They all implement the TYPO3\TYPO3CR\Migration\Filters\FilterInterface. Custom filters can be developed against that interface as well, just use the fully qualified class name for those when specifying which filter to use.

Here is an example of a migration, Version20140708120530.yaml, that operates on nodes in the “live” workspace that are marked as removed and applies the RemoveNode transformation on them:

up:
  comments: 'Delete removed nodes that were published to "live" workspace'
  warnings: 'There is no way of reverting this migration since the nodes will be deleted in the database.'
  migration:
    -
      filters:
        -
          type: 'IsRemoved'
          settings: []
        -
          type: 'Workspace'
          settings:
            workspaceName: 'live'
      transformations:
        -
          type: 'RemoveNode'
          settings: []

down:
  comments: 'No down migration available'

Like all migrations the file should be placed in a package inside the Migrations/TYPO3CR folder where it will be picked up by the CLI tools provided with the content repository:

  • ./flow node:migrationstatus
  • ./flow node:migrate

Use ./flow help <command> to get detailed instructions. The migrationstatus command also prints a short description for each migration.

Transformations Reference

AddDimensions

Add dimensions on a node. This adds to the existing dimensions, if you need to overwrite existing dimensions, use SetDimensions.

Options Reference:

dimensionValues (array)
An array of dimension names and values to set.
addDefaultDimensionValues (boolean)
Whether to add the default dimension values for all dimensions that were not given.
AddNewProperty

Add a new property with the given value.

Options Reference:

newPropertyName (string)
The name of the new property to be added.
value (mixed)
Property value to be set.
ChangeNodeType

Change the node type.

Options Reference:

newType (string)
The new Node Type to use as a string.
ChangePropertyValue

Change the value of a given property.

This can apply two transformations:

  • If newValue is set, the value will be set to this, with any occurrences of the currentValuePlaceholder replaced with the current value of the property.
  • If search and replace are given, that replacement will be done on the value (after applying the newValue, if set).

This would simply override the existing value:

transformations:
  -
    type: 'ChangePropertyValue'
    settings:
      property: 'title'
      newValue: 'a new value'

This would prefix the existing value:

transformations:
  -
    type: 'ChangePropertyValue'
    settings:
      property: 'title'
      newValue: 'this is a prefix to {current}'

This would prefix existing value and then apply search/replace on the result:

transformations:
  -
    type: 'ChangePropertyValue'
    settings:
      property: 'title'
      newValue: 'this is a prefix to {current}'
      search: 'something'
      replace: 'something else'

And in case your value contains the magic string “{current}” and you need to leav it intact, this would prefix the existing value but use a different placeholder:

transformations:
  -
    type: 'ChangePropertyValue'
    settings:
      property: 'title'
      newValue: 'this is a prefix to {__my_unique_placeholder}'
      currentValuePlaceholder: '__my_unique_placeholder'

Options Reference:

property (string)
The name of the property to change.
newValue (string)

New property value to be set.

The value of the option currentValuePlaceholder (defaults to “{current}”) will be used to include the current property value into the new value.

search (string)
Search string to replace in current property value.
replace (string)
Replacement for the search string.
currentValuePlaceholder (string)
The value of this option (defaults to {current}) will be used to include the current property value into the new value.
RemoveNode

Removes the node.

RemoveProperty

Remove the property.

Options Reference:

property (string)
The name of the property to be removed.
RenameDimension

Rename a dimension.

Options Reference:

newDimensionName (string)
The new name for the dimension.
oldDimensionName (string)
The old name of the dimension to rename.
RenameNode

Rename a node.

Options Reference:

newName (string)
The new name for the node.
RenameProperty

Rename a given property.

Options Reference:

from (string)
The name of the property to change.
to (string)
The new name for the property to change.
SetDimensions

Set dimensions on a node. This always overwrites existing dimensions, if you need to add to existing dimensions, use AddDimensions.

Options Reference:

dimensionValues (array)
An array of dimension names and values to set.
addDefaultDimensionValues (boolean)
Whether to add the default dimension values for all dimensions that were not given.
StripTagsOnProperty

Strip all tags on a given property.

Options Reference:

property (string)
The name of the property to work on.

Filters Reference

DimensionValues

Filter nodes by their dimensions.

Options Reference:

dimensionValues (array)
The array of dimension values to filter for.
filterForDefaultDimensionValues (boolean)
Overrides the given dimensionValues with dimension defaults.
IsRemoved

Selects nodes marked as removed.

NodeName

Selects nodes with the given name.

Options Reference:

name (string)
The value to compare the node name against, strict equality is checked.
NodeType

Selects nodes by node type.

Options Reference:

nodeType (string)
The node type name to match on.
withSubTypes (boolean)
Whether the filter should match also on all subtypes of the configured node type. Note: This can only be used with node types still available in the system!
exclude (boolean)
Whether the filter should exclude the given NodeType instead of including only this node type.
PropertyNotEmpty

Filter nodes having the given property and its value not empty.

Options Reference:

propertyName (string)
The property name to be checked for non-empty value.
Workspace

Filter nodes by workspace name.

Options Reference:

workspaceName (string)
The workspace name to match on.

Contribute

Development

Developing Neos.

Neos UI Development

Setting up your machine for Neos UI development

For user interface development of Neos we utilize grunt and some other tools.

Setting up your machine could be done by using the installation script that can be found in TYPO3.Neos/Scripts/install-dev-tools.sh. If you want to do a manual installation you will need to install the following software:

  • nodejs
  • npm
  • grunt-cli (global, sudo npm install -g grunt-cli)
  • requirejs (sudo npm install -g requirejs)
  • bower (sudo npm install -g bower)
  • bundler (sudo gem install bundler)
  • sass & compass (sudo gem install sass compass)

Note

Make sure you call npm install, bundle install --binstubs --path bundle and bower install before running the grunt tasks.

Grunt tasks types

We have different types of grunt tasks. All tasks have different purposes:

  • build commands

    Those commands are used to package a production version of the code. Like for example minified javascript, minified css or rendered documentation.

  • compile commands

    Those commands are meant for compiling resources that are used in development context. This could for example be a packed file containing jquery and related plugins which are loaded in development context using requirejs.

  • watch commands

    Those commands are used for watching file changes. When a change is detected the compile commands for development are executed. Use those commands during your daily work for a fast development experience.

  • test commmands

    Used for running automated tests. Those tests use phantomjs which is automatically installed by calling npm install. Phantomjs needs some other dependencies though, check TYPO3.Neos/Scripts/install-phantomjs-dependencies.sh for ubuntu based systems.

Available grunt tasks
Build
  • grunt build

    Executes grunt build-js and grunt build-css.

  • grunt build-js

    Builds the minified and concatenated javascript sources to ContentModule-built.js using requirejs.

  • grunt build-css

    Compiles and concatenates the css sources to Includes-built.css.

  • grunt build-docs

    Renders the documentation. This task depends on a local installation of Omnigraffle.

Compile
  • grunt compile

    Executes grunt compile-js and grunt compile-css

  • grunt compile-js

    Compiles the javascript sources. This is the task to use if you want to package the jquery sources including plugins or if you want to recreated the wrapped libraries we include in Neos. During this process some of the included libraries are altered to prevent collisions with Neos or the website frontend.

  • grunt compile-css

    Compiles and concatenates the scss sources to css.

Watch
  • watch-css

    Watches changes to the scss files and runs compile-css if a change is detected.

  • watch-docs

    Watches changes to the rst files of the documentation, and executes a compilation of all restructured text sources to html. This task depends on a local sphinx install but does not require Omnigraffle.

  • watch

    All of the above.

Test
  • grunt test

    Runs QUnit tests for javascript modules.

Documentation

Improving the Neos documentation.

Neos Documentation

How it works

We use Read The Docs (http://neos.readthedocs.org) to host the documentation for Neos. This service listens for commits on Github and automatically builds the documentation for all branches.

The entire documentation of Neos is located inside the Neos development collection (https://github.com/neos/neos-development-collection) and can be edited by forking the repository, editing the files and creating a pull request.

reStructuredText

The markup language that is used by Sphinx is [reStructuredText](http://docutils.sourceforge.net/rst.html), a plaintext markup syntax that easy to edit using any text editor and provides the possibility to write well organized documentations that can be rendered in multiple output formats by e.g. Sphinx.

Sphinx

Sphinx is a generator that automates building documentations from reStructuredText markup. It can produce HTML, LaTex, ePub, plain text and many more output formats.

As Sphinx is a python based tool, you can install it by using either pip:

pip install -U Sphinx

or easy_install:

easy_install -U Sphinx

Makefile

As Sphinx accepts many options to build the many output formats, we included a Makefile to simplify the building process.

In order to use the commands you must already have Sphinx installed.

You can get an overview of the provided commands by

cd TYPO3.Neos/Documentation

make help

Docker

If you don’t want to install Sphinx on your computer or have trouble installing it, you can use a prebuilt Docker image that contains a working version of Sphinx. The image is built on top of a pretty small alpine linux and has only around 80MB.

You can simply prefix your make command with the following docker command:

docker run -v $(pwd):/documents hhoechtl/doctools-sphinx make html

This will fire up a docker-container built from that image and execute the Sphinx build inside the container. As your current directory is mounted into the container, it can read the files and the generated output will be written in your local filesystem as it would by just executing the make command with your local Sphinx installation.

How To’s

Neos Best Practices (to be written)

Adding A Simple Contact Form

Using the TYPO3.Form package you can easily create and adopt simple to very complex forms. For it to work properly you just have to define where it should find its form configurations.

Yaml (Sites/Vendor.Site/Configuration/Settings.yaml)

TYPO3:
  Form:
    yamlPersistenceManager:
      savePath: 'resource://Vendor.Site/Private/Form/'

Now place a valid TYPO3.Form Yaml configuration in the Private/Form folder. Then add a Form Element where you wish the form to be displayed and select it from the dropdown in the Inspector.

Yaml (Sites/Vendor.Site/Resources/Private/Form/contact-form.yaml)

type: 'TYPO3.Form:Form'
identifier: contact-form
label: Contact
renderingOptions:
  submitButtonLabel: Send
renderables:
  -
    type: 'TYPO3.Form:Page'
    identifier: page-one
    label: Contact
    renderables:
      -
        type: 'TYPO3.Form:SingleLineText'
        identifier: name
        label: Name
        validators:
          - identifier: 'TYPO3.Flow:NotEmpty'
        properties:
          placeholder: Name
        defaultValue: ''
      -
        type: 'TYPO3.Form:SingleLineText'
        identifier: email
        label: E-Mail
        validators:
          - identifier: 'TYPO3.Flow:NotEmpty'
          - identifier: 'TYPO3.Flow:EmailAddress'
        properties:
          placeholder: 'E-Mail'
        defaultValue: ''
      -
        type: 'TYPO3.Form:MultiLineText'
        identifier: message
        label: Message
        validators:
          - identifier: 'TYPO3.Flow:NotEmpty'
        properties:
          placeholder: 'Your Message'
        defaultValue: ''
finishers:
  -
    identifier: 'TYPO3.Form:Email'
    options:
      templatePathAndFilename: resource://Vendor.Site/Private/Templates/Email/Message.txt
      subject: Contact from example.net
      recipientAddress: office@example.net
      recipientName: 'Office of Company'
      senderAddress: server@example.net
      senderName: Server example.net
      replyToAddress: office@example.net
      format: plaintext
  -
    identifier: 'TYPO3.Form:Confirmation'
    options:
      message: >
        <h3>Thank you for your feedback</h3>
        <p>We will process it as soon as possible.</p>

In this example we are using the TYPO3.Form:Email Finisher. The Email Finisher requires the TYPO3.SwiftMailer package to be installed. It sends an E-Mail using the defined template and settings. By the second Finisher a confirmation is displayed.

Html (Sites/Vendor.Site/Resources/Private/Templates/Email/Message.txt)

Hello,

<f:for each="{form.formState.formValues}" as="value" key="label">
  {label}: {value}
</f:for>

Thanks

To find out more about how to create forms see the TYPO3.Form package. There is even a Click Form Builder that exports the Yaml settings files.

Warning

Make sure the Neos.Demo package (or other) is deactivated. Otherwise the setting TYPO3.Form.yamlPersistenceManager.savePath may be overwritten by another package. You can deactivate a package with the command ./flow package:deactivate <PackageKey>.

Changing the Body Class with a condition

In some cases there is the need to define different body classes based on a certain condition.

It can for example be that if a page has sub pages then we want to add a body class tag for this.

TypoScript code:

page {
    bodyTag {
        attributes.class = ${q(node).children().count() > 1 ? 'has-subpages' : ''}
    }
}

First of all we add the part called bodyTag to the TypoScript page object. Then inside we add the attributes.class.

Then we add a FlowQuery that checks if the current node has any children. If the condition is true then the class “has-subpages” is added to the body tag on all pages that have any children.

An other example could be that we want to check if the current page is of type page.

TypoScript code:

page {
    bodyTag {
        attributes.class = ${q(node).filter('[instanceof TYPO3.Neos:Page]') != '' ? 'is-page' : ''}
    }
}

Changing Defaults Depending on Content Placement

Let’s say we want to adjust our YouTube content element depending on the context: By default, it renders in a standard YouTube video size; but when being used inside the sidebar of the page, it should shrink to a width of 200 pixels. This is possible through nested prototypes:

page.body.contentCollections.sidebar.prototype(My.Package:YouTube) {
  width = '200'
  height = '150'
}

Essentially the above code can be read as: “For all YouTube elements inside the sidebar of the page, set width and height”.

Let’s say we also want to adjust the size of the YouTube video when being used in a ThreeColumn element. This time, we cannot make any assumptions about a fixed TypoScript path being rendered, because the ThreeColumn element can appear both in the main column, in the sidebar and nested inside itself. However, we are able to nest prototypes into each other:

prototype(ThreeColumn).prototype(My.Package:YouTube) {
  width = '200'
  height = '150'
}

This essentially means: “For all YouTube elements which are inside ThreeColumn elements, set width and height”.

The two possibilities above can also be flexibly combined. Basically this composability allows to adjust the rendering of websites and web applications very easily, without overriding templates completely.

After you have now had a head-first start into TypoScript based on practical examples, it is now time to step back a bit, and explain the internals of TypoScript and why it has been built this way.

Creating a simple Content Element

If you need some specific content element, you can easly create a new Node Type with an attached HTML template. To add a new Node Type, follow this example, just replace “Vendor” by your own vendor prefix:

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml):

'Vendor:YourContentElementName':
  superTypes:
    'TYPO3.Neos:Content': TRUE
  ui:
    label: 'My first custom content element'
    group: 'general'
    inspector:
      groups:
        image:
          label: 'Image'
          icon: 'icon-image'
          position: 1
  properties:
    headline:
      type: string
      defaultValue: 'Replace by your headline value ...'
      ui:
        label: 'Headline'
        inlineEditable: TRUE
    subheadline:
      type: string
      defaultValue: 'Replace by your subheadline value ...'
      ui:
        label: 'Subheadline'
        inlineEditable: TRUE
    text:
      type: string
      ui:
        label: 'Text'
        reloadIfChanged: TRUE
    image:
      type: TYPO3\Media\Domain\Model\ImageInterface
      ui:
        label: 'Image'
        reloadIfChanged: TRUE
        inspector:
          group: 'image'

Based on your Node Type configuration, now you need a TypoScript object to be able to use your new Node Type. This TypoScript object needs to have the same name as the Node Type:

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScripts/Library/Root.ts2):

prototype(Vendor:YourContentElementName) < prototype(TYPO3.Neos:Content) {
        templatePath = 'resource://Vendor.Site/Private/Templates/TypoScriptObjects/YourContentElementName.html'

        headline = ${q(node).property('headline')}
        subheadline = ${q(node).property('subheadline')}
        text = ${q(node).property('text')}
        image = ${q(node).property('image')}
}

Last thing, add the required Fluid template:

HTML (Vendor.Site/Private/Templates/TypoScriptObjects/YourContentElementName.html):

{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace media=TYPO3\Media\ViewHelpers}
<article>
        <header>
                {neos:contentElement.editable(property: 'headline', tag: 'h2')}
                {neos:contentElement.editable(property: 'subheadline', tag: 'h3')}
        </header>
        <div>
                {neos:contentElement.editable(property: 'text')}
                <f:if condition="{image}"><media:image image="{image}" maximumWidth="300" alt="{headline}" /></f:if>
        </div>
</article>

Now, if you try to add a new Node in your page, you should see your new Node Type. Enjoy editing with Neos.

Customize Login Screen

You can customize the login screen by editing your Settings.yaml:

TYPO3:
  Neos:
    userInterface:
      backendLoginForm:
        backgroundImage: 'resource://Your.Package/Public/Images/LoginScreen.jpg'

Or alternatively add a custom stylesheet:

TYPO3:
  Neos:
    userInterface:
      backendLoginForm:
        stylesheets:
          'Your.Package:CustomStyles': 'resource://Your.Package/Public/Styles/Login.css'

Note

In this case Your.Package:CustomStyles is a simple key, used only internally.

How to disable a stylesheet ?

You can disable existing stylesheets, by setting the value to FALSE, the following snippet will disable the stylesheet provided by Neos, so your are free to implement your own:

TYPO3:
  Neos:
    userInterface:
      backendLoginForm:
        stylesheets:
          'TYPO3.Neos:DefaultStyles': FALSE
          'Your.Package:CustomStyles': 'resource://Your.Package/Public/Styles/Login.css'

Extending the Page

In Neos the page is a simple Node Type named TYPO3.Neos:Page, you can directly extend this Node Type to add specific properties. Below you will find a simple example for adding a page background image:

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml)

'TYPO3.Neos.NodeTypes:Page':
  ui:
    inspector:
      groups:
        background:
          label: 'Background'
          position: 900
  properties:
    backgroundImage:
      type: TYPO3\Media\Domain\Model\ImageInterface
      ui:
        label: 'Image'
        reloadPageIfChanged: TRUE
        inspector:
          group: 'background'

With this configuration, when you click on the page, you will see the Image editor in the Inspector.

To access the backgroundImage in your page template you can also modify the TYPO3.Neos:Page TypoScript object, like in the below example:

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScripts/Library/Root.ts2)

prototype(TYPO3.Neos:Page) {
        body.backgroundImage = ${q(node).property('backgroundImage')}
}

With TYPO3.Media ViewHelper you can display the Image with the follwing HTML snippet:

HTML

{namespace media=TYPO3\Media\ViewHelpers}
<style>
html {
        margin:0;
        padding:0;
        background: url({media:uri.image(image:backgroundImage)}) no-repeat center fixed;
        -webkit-background-size: cover;
        -moz-background-size: cover;
        -o-background-size: cover;
        background-size: cover;
}
</style>

Integrating a JavaScript-based slider

If you want to integrate a Slider into your page as content element or as part of your template and want edit it in the backend you have do some simple steps.

First you have to use a slider javscript plugin which initializes itself when added to the page after page load. Or you write your own initialization code into a javascript function which you then add as callback for the neos backend events.

For this example the carousel plugin and styling from bootstrap 3.0 has been used: http://getbootstrap.com/javascript/#carousel

To create the basic content element you have to add it to your node types.

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml):

'Vendor.Site:Carousel':
  superTypes:
    'TYPO3.Neos:Content': TRUE
  childNodes:
    carouselItems:
      type: 'TYPO3.Neos:ContentCollection'
  ui:
    label: 'Carousel'
    group: 'plugins'
    icon: 'icon-picture'
    inlineEditable: TRUE

Next you need to define the prototype for the slider in typoscript.

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScript/NodeTypes/Carousel.ts2):

prototype(Vendor.Site:Carousel) {
        carouselItems = TYPO3.Neos:ContentCollection {
                nodePath = 'carouselItems'
                content.iterationName = 'carouselItemsIteration'
                attributes.class = 'carousel-inner'
        }

        // Collect the carousels children but only images
        carouselItemArray = ${q(node).children('carouselItems').children('[instanceof TYPO3.Neos.NodeTypes:Image]')}

        // Enhance image prototype when inside the carousel
        prototype(TYPO3.Neos.NodeTypes:Image) {
                // Render images in the carousel with a special template.
                templatePath = 'resource://Vendor.Site/Private/Templates/TypoScriptObjects/CarouselItem.html'

                // The first item should later be marked as active
                attributes.class = ${'item' + (carouselItemsIteration.isFirst ? ' active' : '')}

                // We want to use the item iterator in fluid so we have to store it as variable.
                iteration = ${carouselItemsIteration}
        }
}

Now you need to include this at the top of your (Sites/Vendor.Site/Resources/Private/TypoScript/Root.ts2):

// Includes all additional ts2 files inside the NodeTypes folder
include: NodeTypes/*.ts2

For rendering you need the fluid templates for the slider.

Html (Sites/Vendor.Site/Private/Templates/NodeTypes/Carousel.html)

{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace ts=TYPO3\TypoScript\ViewHelpers}
<div{attributes -> f:format.raw()}>
        <div class="carousel slide" id="{node.identifier}">
                <!-- Indicators -->
                <ol class="carousel-indicators">
                        <f:for each="{carouselItemArray}" as="item" iteration="itemIterator">
                                <li data-target="#{node.identifier}" data-slide-to="{itemIterator.index}" class="{f:if(condition: itemIterator.isFirst, then: 'active')}"></li>
                        </f:for>
                </ol>

                <!-- Wrapper for slides -->
                {carouselItems -> f:format.raw()}

                <!-- Controls -->
                <a class="left carousel-control" href="#{node.identifier}" data-slide="prev">
                        <span class="icon-prev"></span>
                </a>
                <a class="right carousel-control" href="#{node.identifier}" data-slide="next">
                        <span class="icon-next"></span>
                </a>
        </div>
</div>

And now the fluid template for the slider items.

Html (Sites/Vendor.Site/Private/Templates/TypoScriptObjects/CarouselItem.html)

{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace media=TYPO3\Media\ViewHelpers}
<div{attributes -> f:format.raw()}>
        <f:if condition="{image}">
                <f:then>
                        <media:image image="{image}" alt="{alternativeText}" title="{title}" maximumWidth="{maximumWidth}" maximumHeight="{maximumHeight}" />
                </f:then>
                <f:else>
                        <img src="{f:uri.resource(package: 'TYPO3.Neos', path: 'Images/dummy-image.svg')}" title="Dummy image" alt="Dummy image" />
                </f:else>
        </f:if>
        <div class="carousel-caption">
                <f:if condition="{hasCaption}">
                        {neos:contentElement.editable(property: 'caption')}
                </f:if>
        </div>
</div>

For styling you can simply include the styles provided in bootstrap into your page template.

Html

<link rel="stylesheet" href="{f:uri.resource(path: '3/css/bootstrap.min.css', package: 'TYPO3.Twitter.Bootstrap')}" media="all" />

If you want to hide specific parts of a plugin while in backend you can use the provided neos-backend class.

Css

.neos-backend .carousel-control {
        display: none;
}

Don’t forget to include the javascript for the plugin from the bootstrap package into your page template.

Html

<script src="{f:uri.resource(path: '3/js/bootstrap.min.js', package: 'TYPO3.Twitter.Bootstrap')}"></script>

Now, you should be able to add the new ‘Carousel’ node type as content element.

Rendering a Menu

The implementation of a menu is done in TypoScript and HTML, this gives an flexibility in what can be rendered.

First of all you have to add a new element (with a name) in TypoScript that is of type Menu. Then inside the TypoScript object you can set what kind of rendering (templatePath) to use, an entryLevel and a maximumLevels properties.

TypoScript code:

mainMenu = Menu
mainMenu {
    templatePath = 'resource://VendorName.VendorSite/Private/Templates/TypoScriptObjects/MainMenu.html'
    entryLevel = 1
    maximumLevels = 0
}

The example above sets first a templatePath for the mainMenu object, then the level to start finding nodes from is set to level 1. It will only take nodes on the current level because of the property maximumLevels is set to 0.

If you want a custom rendering of my menu items then you need to add a template. This template renders a ul list that has a link to a node.

Full HTML code:

{namespace neos=TYPO3\Neos\ViewHelpers}
<ul class="nav">
    <f:for each="{items}" as="item">
        <li class="menu-item">
            <neos:link.node node="{item.node}" />
        </li>
    </f:for>
</ul>

What is done is first to include a viewhelper to being able to link my nodes inside the HTML. The namespace in the example is neos to clarify from where the viewhelper is taken.

Viewhelper include:

{namespace neos=TYPO3\Neos\ViewHelpers}

The next thing is to iterate through the nodes found by TypoScript.

Iterating through nodes:

<f:for each="{items}" as="item">
    ...
</f:for>

What then is done inside the iteration is that first we wrap our node with a li tag with a class called menu-item. Then we use our viewhelper to (which namespace is neos in this example) link it to a node in Neos. The linking is set in the parameter node, the you can chose what should be shown as a text for the link. In this case the label (default) of the node is the text.

Wrapping and linking of node:

<li class="menu-item">
    <neos:link.node node="{item.node}" />
</li>

Rendering a Meta-Navigation

To render a meta navigation (ex: footer navigation) in Neos all you need to use is TypoScript and HTML.

A common fact is that most sites have footer where all pages are using the same content or information. So a common issue is how to solve this in the best possible way.

VendorName.VendorSite/Resources/Private/TypoScripts/Library/Root.ts2

TypoScript code:

page.body {
    metaMenu = Menu
    metaMenu {
        entryLevel = 2
        templatePath = 'resource://VendorName.VendorSite/Private
        /Templates/TypoScriptObjects/MetaMenu.html'
        maximumLevels = 1
        startingPoint = ${q(site).children('[uriPathSegment="metamenu"]').get(0)}
    }
}

The first thing that we define inside the page.body is a Menu object that is called metaMenu. The options available in this example is:

  • entryLevel: On which level in the page structure the menu should start.
  • templatePath: The path to the template where the rendering is done.
  • maximumLevels: How many levels the menu can show.
  • startingPoint: The starting point of the menu, in this case the node with name ‘nameOfNode’ is the starting point.

HTML template code:

{namespace neos=TYPO3\Neos\ViewHelpers}
<nav class="nav">
    <ul class="nav nav-pills">
        <f:for each="{items}" as="item" iteration="menuItemIterator">
            <li class="{item.state}">
                <neos:link.node node="{item.node}" />
            </li>
        </f:for>
    </ul>
</nav>

What is done is first to include a view helper to be able to link to nodes inside the HTML. The namespace in the example is neos to clarify from where the viewhelper is taken.

Viewhelper include:

{namespace neos=TYPO3\Neos\ViewHelpers}

The next thing is to iterate through the nodes found by TypoScript.

Iterating through nodes:

<f:for each="{items}" as="item">
    ...
</f:for>

What then is done inside the iteration is that first we wrap our node with a li tag with a class called menu-item. Then we use our view helper to (which namespace is neos that is clarified) link it to a node in Neos. The linking is set in the parameter node, the you can choose what should be shown as a text for the link. In this case the label (default) of the node is the text.

Wrapping and linking of node:

<li class="{item.state}">
    <neos:link.node node="{item.node}" />
</li>

The last thing to do is to include the meta menu to our page layout(s).

Include meta menu:

{parts.metaMenu -> f:format.raw()}

Selecting a Page Layout

Neos has a flexible way of choosing a layout, which can be selected in the backend.

First of all, the necessary layouts have to be configured inside VendorName.VendorSite/Configuration/NodeTypes.yaml:

'TYPO3.Neos.NodeTypes:Page':
  properties:
    layout:
      ui:
        inspector:
          group: layout
          editorOptions:
            values:
              'default':
                label: 'Default'
              'landingPage':
                label: 'Landing page'
    subpageLayout:
      ui:
        inspector:
          group: layout
          editorOptions:
            values:
              'default':
                label: 'Default'
              'landingPage':
                label: 'Landing page'

Here, the properties layout and subpageLayout are configured inside TYPO3.Neos:Page:

  • layout: Changes the layout of the current page
  • subpageLayout: Changes the layout of subpages if nothing else was chosen.

Note

Notice that the group is set for both properties as well, because they’re hidden by default.

When all this is done we need to bind the layout to a rendering and this is done in TypoScript, f.e. in VendorName.VendorSite/Resources/Private/TypoScripts/Library/Root.ts:

page.body {
    // standard "Page" configuration
}

default < page

landingPage < page
landingPage.body {
    templatePath = 'resource://VendorName.VendorSite/Private/Templates/Page/LandingPage.html'
}

If a page layout was chosen, that is the TypoScript object path where rendering starts. For example, if the landingPage was chosen, a different template can be used.

The implementation internal of the layout rendering can be found in the file:

TYPO3.Neos/Resources/Private/TypoScript/DefaultTypoScript.ts2

The element root.layout is the one responsible for handling the layout. So when trying to change the layout handling this is the TypoScript object to manipulate.

Select Template based on NodeType

It is also possible to select the page rendering configuration based on the node type of the page. Let’s say you have a node type named VendorName.VendorSite:Employee which has TYPO3.Neos.NodeTypes:Page as a supertype. This node type is used for displaying a personal page of employees working in your company. This page will have a different structure compared to your basic page.

The right approach would be to create a TypoScript prototype for your default page and employee page like:

prototype(VendorName.VendorSite:Page) < prototype(TYPO3.Neos:Page) {
    body.templatePath = 'resource://VendorName.VendorSite/Private/Templates/Page/Default.html'
    # Your further page configuration here
}

prototype(VendorName.VendorSite:EmployeePage) < prototype(VendorName.VendorSite:Page) {
    body.templatePath = 'resource://VendorName.VendorSite/Private/Templates/Page/Employee.html'
    # Your further employee page configuration here
}

But now how to link this TypoScript path to your node type? For this we can have a look at the TypoScript root path. This root path is a TYPO3.TypoScript:Case object, which will render the /page path by default. But you can add your own conditions to render a different path.

In our case we will add a condition on the first position of the condition:

root.employeePage {
    condition = ${q(node).is('[instanceof VendorName.VendorSite:Employee]')}
    renderPath = '/employeePage'
}

page = VendorName.VendorSite:Page
employeePage = VendorName.VendorSite:EmployeePage

This will now render the employeePage TypoScript path if a page of type VendorName.VendorSite:Employee is rendered on your website.

Using a DefaultPage Prototype

This is an alternative and more flexible approach to the Select Template based on NodeType method descriped above. First we adjust the default root matcher not to render the /page path, but a prototype derived from the current document node type name instead:

root {
    default {
        type = ${q(node).property('_nodeType') + '.Document'}
        renderPath >
    }
}

Instead of simply defining our page object inside root.ts2, we create a new prototype based on a page prototype. The content will basically remain the same, make sure only to define bare essentials that all your future custom page types can profit from.

Your basic DefaultPage prototype could look something like this:

prototype(VendorName:DefaultPage) < prototype(Page) {
    head {
        stylesheets {
            site = TYPO3.TypoScript:Template {
                templatePath = 'resource://VendorName.VendorSite/Private/Templates/Includes/InlineStyles.html'
                sectionName = 'stylesheets'
            }

            mainStyle  = TYPO3.TypoScript:Tag {
                tagName = 'link'
                attributes {
                    rel = 'stylesheet'
                    href = TYPO3.TypoScript:ResourceUri {
                        path = 'resource://VendorName.VendorSite/Public/Styles/Styles.css'
                    }
                }
            }
        }
    }
    body {
        templatePath = 'resource://VendorName.VendorSite/Private/Templates/Page/Default.html'
        sectionName = 'body'
    }
}

Now we define our basic prototype for all TYPO3.Neos.NodeTypes:Page nodes. Since we extend VendorName:DefaultPage here, we can only define custom needs for TYPO3.Neos.NodeTypes:Page node types.

For example:

prototype(TYPO3.Neos.NodeTypes:Page.Document) < prototype(VendorName:DefaultPage) {
    body {
        content {
            main = PrimaryContent {
            nodePath = 'main'
            }
        }
    }
}

All our custom document node types will be defined like this:

prototype(VendorName:Product.Document) < prototype(VendorName:DefaultPage) {
    # custom properties for your node type
}

In case we have a layout property within our node type configuration, we can define a prototype for this case too:

customLayout = TYPO3.Neos.NodeTypes:Page.Document {
   # custom properties for your node type
}

Translating content

Translations for content are based around the concept of Content Dimensions. The dimension language can be used for most translation scenarios. This cookbook shows how to set up the dimension, migrate existing content to use dimensions and how to work with translations.

Dimension configuration

The first step is to configure a language dimension with a dimension preset for each language. This should be done in the file Configuration/Settings.yaml of your site package:

TYPO3:
  TYPO3CR:
    contentDimensions:
      'language':
        label: 'Language'
        icon: 'icon-language'
        default: 'en'
        defaultPreset: 'en'
        presets:
          'en':
            label: 'English'
            values: ['en']
            uriSegment: 'english'
          'fr':
            label: 'Français'
            values: ['fr', 'en']
            uriSegment: 'francais'
          'de':
            label: 'Deutsch'
            values: ['de', 'en']
            uriSegment: 'deutsch'

This will configure a dimension language with a default dimension value of en, a default preset en and some presets for the actual available dimension configurations. Each of these presets represents one language that is available for display on the website.

As soon as a dimension with presets is configured, the content module will show a dimension selector to select presets for each dimension. This can be used in combination with a language menu on the website.

Note

Neos 1.2 only supports translation of existing content by using fallbacks. In the example there is a fallback from fr to en in the fr dimension preset. While it is possible to work without a default language and fallbacks, no existing content can be translated in this case. This restriction is removed with Neos 1.3.

Migration of existing content

Existing content of a site needs to be migrated to use the dimension default value, otherwise no nodes would be found. This can be done with a node migration which is included in the TYPO3.TYPO3CR package:

./flow node:migrate 20150716212459

This migration has to be applied whenever a new dimension is configured to set the default value on all existing nodes.

Integrate Language Menu

A simple language menu can be displayed on the site by using the TYPO3.Neos:DimensionsMenu TypoScript object:

page {
    body {
        parts {
            languageMenu = TYPO3.Neos:DimensionsMenu {
                dimension = 'language'
            }
        }
    }
}

This will render a <ul> with links to node variants in other languages of the current document node with a label from a dimension preset. Of course the template can be customized for custom output with the templatePath property.

Working with translated content

All content that needs to be translated should go into the default preset first. After selecting a different preset either using the dimension selector or a language menu, the default content will shine through. As soon as a shine-through node is updated, it will be automatically copied to a new node variant with the most specific dimension value in the fallback list.

Wrapping a List of Content Elements

Create a simple Wrapper that can contain multiple content Elements.

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml)

'Vendor:Box':
  superTypes:
    'TYPO3.Neos:Content': TRUE
  ui:
    group: structure
    label: Box
    icon: icon-columns
    inlineEditable: true
  childNodes:
    column0:
      type: 'TYPO3.Neos:ContentCollection'

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScripts/Library/NodeTypes.ts2)

prototype(Vendor:Box) < prototype(TYPO3.Neos:Content) {
        templatePath = 'resource://Vendor.Site/Private/Templates/TypoScriptObjects/Box.html'
        columnContent = TYPO3.Neos:ContentCollection
        columnContent {
                nodePath = 'column0'
        }
}

Html (Sites/Vendor.Site/Private/Templates/TypoScriptObjects/Box.html)

{namespace ts=TYPO3\TypoScript\ViewHelpers}

<div class="container box">
        <div class="column">
                <ts:render path="columnContent" />
        </div>
</div>

Extending it to use an option

You can even simply extend the box to provide a checkbox for different properties.

Yaml (Sites/Vendor.Site/Configuration/NodeTypes.yaml)

'Vendor:Box':
  superTypes:
    'TYPO3.Neos:Content': TRUE
  ui:
    group: structure
    label: Box
    icon: icon-columns
    inlineEditable: TRUE
    inspector:
      groups:
        display:
          label: Display
          position: 5
  properties:
    collapsed:
      type: boolean
      ui:
        label: Collapsed
        reloadIfChanged: TRUE
        inspector:
          group: display
  childNodes:
    column0:
      type: 'TYPO3.Neos:ContentCollection'

TypoScript (Sites/Vendor.Site/Resources/Private/TypoScripts/Library/NodeTypes.ts2)

prototype(Vendor:Box) < prototype(TYPO3.Neos:Content) {
        templatePath = 'resource://Vendor.Site/Private/Templates/TypoScriptObjects/Box.html'
        columnContent = TYPO3.Neos:ContentCollection
        columnContent {
                nodePath = 'column0'
        }
        collapsed = ${q(node).property('collapsed')}
}

Html (Sites/Vendor.Site/Private/Templates/TypoScriptObjects/Box.html)

{namespace ts=TYPO3\TypoScript\ViewHelpers}

<f:if condition="{collapsed}">
        <button>open the collapsed box via js</button>
</f:if>
<div class="container box {f:if(condition: collapsed, then: 'collapsed', else: '')}">
        <div class="column">
                <ts:render path="columnContent" />
        </div>
</div>

Neos Operations

Command Line Tools

Neos comes with a number of command line tools to ease setup and maintenance. These tools can be used manually or be added to automated deployments or cron jobs. This section gives a high level overview of the available tools.

More detailed instructions on the use of the command line tools can be displayed using the help command:

./flow help                     # lists all available command
./flow help <packageKey>        # lists commands provided in package
./flow help <commandIdentifier> # show help for specific command

Here is an example:

./flow help user:addrole

Add a role to a user

COMMAND:
  typo3.neos:user:addrole

USAGE:
  ./flow user:addrole [<options>] <username> <role>

ARGUMENTS:
  --username           The username of the user
  --role               Role to be added to the user, for example
                       "TYPO3.Neos:Administrator" or just "Administrator

OPTIONS:
  --authentication-provider Name of the authentication provider to use. Example:
                       "Typo3BackendProvider

DESCRIPTION:
  This command allows for adding a specific role to an existing user.

  Roles can optionally be specified as a comma separated list. For all roles provided by Neos, the role
  namespace "TYPO3.Neos:" can be omitted.

  If an authentication provider was specified, the user will be determined by an account identified by "username"
  related to the given provider. However, once a user has been found, the new role will be added to all
  existing accounts related to that user, regardless of its authentication provider.

User Management

These commands allow to manage users. To create an user with administrative privileges, this is needed:

./flow user:create john@doe.com pazzw0rd John Doe --roles TYPO3.Neos:Administrator
Command Description
user:list List all users
user:show Shows the given user
user:create Create a new user
user:delete Delete a user
user:activate Activate a user
user:deactivate Deactivate a user
user:setpassword Set a new password for the given user
user:addrole Add a role to a user
user:removerole Remove a role from a user

Workspace Management

The commands to manage workspaces reflect what is possible in the Neos user interface. They allow to list, create and delete workspaces as well as publish and discard changes.

One notable difference is that rebasing a workspace is possivle from the command line even if it contains unpublished changes.

Command Description
workspace:publish Publish changes of a workspace
workspace:discard Discard changes in workspace
workspace:create Create a new workspace
workspace:delete Deletes a workspace
workspace:rebase Rebase a workspace
workspace:list Display a list of existing workspaces

Site Management

Command Description
domain:add Add a domain record
domain:list Display a list of available domain records
domain:delete Delete a domain record
domain:activate Activate a domain record
domain:deactivate Deactivate a domain record
site:import Import sites content
site:export Export sites content
site:prune Remove all content and related data
site:list Display a list of available sites

Appendixes

Contributors

The following is a list of contributors generated from version control information (see below). As such it is neither claiming to be complete nor is the ordering anything but alphabetic.

  • Adrian Föder
  • Alessandro Paterno
  • Alexander Berl
  • Alexander Frühwirth
  • Alexander Kappler
  • Alexander Stehlik
  • Anders Pedersen
  • Andreas Förthner
  • Andreas Wolf
  • Aske Ertmann
  • Bastian Heist
  • Bastian Waidelich
  • Benedikt Schmitz
  • Benno Weinzierl
  • Berit Hlubek
  • Berit Jensen
  • Bernhard Schmitt
  • Carsten Bleicker
  • Carsten Blüm
  • Cedric Ziel
  • Charles Coleman
  • Christian Albrecht
  • Christian Jul Jensen
  • Christian Müller
  • Christian Vette
  • Christoph Dähne
  • Christopher Hlubek
  • Daniel Lienert
  • Denny Lubitz
  • Dmitri Pisarev
  • Dominik Piekarski
  • Dominique Feyer
  • Ernesto Baschny
  • Florian Heinze
  • Florian Weiss
  • Frans Saris
  • Franz Kugelmann
  • Frederic Darmstädter
  • Garvit Khatri
  • Georg Ringer
  • Gerhard Boden
  • Hans Höchtl
  • Helmut Hummel
  • Henjo Hoeksma
  • Ingmar Schlecht
  • Irene Höppner
  • Jacob Floyd
  • Jacob Rasmussen
  • Jan-Erik Revsbech
  • Johannes Steu
  • Jonas Renggli
  • Jose Antonio Guerra
  • Julian Kleinhans
  • Kai Moeller
  • Karsten Dambekalns
  • Kay Strobach
  • Kerstin Huppenbauer
  • Kristin Povilonis
  • Lars Röttig
  • Lars Nieuwenhuizen
  • Lienhart Woitok
  • Marc Neuhaus
  • Marcin Ryzycki
  • Mario Rimann
  • Mario Rudloff
  • Markus Goldbeck
  • Martin Bless
  • Martin Brueggemann
  • Martin Ficzel
  • Martin Helmich
  • Matt Gifford
  • Mattias Nilsson
  • Michael Feinbier
  • Michael Gerdemann
  • Michael Lihs
  • Michiel Roos
  • Moritz Spindelhirn
  • Nils Dehl
  • Pankaj Lele
  • Patrick Reck
  • Raffael Comi
  • Remco Janse
  • Rens Admiraal
  • Robert Lemke
  • Robin Poppenberg
  • Roman Minchyn
  • Samuel Hauser
  • Sascha Nowak
  • Sebastian Helzle
  • Sebastian Kurfürst
  • Sebastian Richter
  • Sebastian Sommer
  • Simon Schaufelberger
  • Soeren Rohweder
  • Søren Malling
  • Stefan Bruggmann
  • Stephan Schuler
  • Thierry Brodard
  • Thomas Allmer
  • Thomas Hempel
  • Tim Kandel
  • Timo Fink
  • Tobias Liebig
  • Tristan Koch
  • Visay Keo
  • Wilhelm Behncke
  • Wouter Wolters

The list has been generated with some manual tweaking of the output of this script contributors.sh executed in Packages/Application:

rm -f contributors.txt
for REPO in `ls` ; do
  if [ -d "$REPO" ]; then
    cd $REPO
    git log --format='%aN' >> ../contributors.txt
    cd ..
  fi
done
sort -u < contributors.txt > contributors-sorted.txt
mv contributors-sorted.txt contributors.txt

Release Notes

1.1.0 (2014-06-19)

The goals for the 1.1 version were performance and stability improvements while providing a proper base for localization support in the next version. The new content cache and other performance improvements will give Neos sites a huge speed boost, eliminating the need for a separate caching proxy for most installations. The content dimension concept is the foundation to work with different content variants and have a very flexible localization solution in Neos. The user interface to work with content dimensions and translations will be part of the next version.

Main highlights are
Performance

Content Cache

The Content Cache is a layer inside the view part of Neos that provides a nested cache for rendered content. It is fully integrated with the Flow caching framework and configurable via TypoScript

Neos comes with the new Content Cache enabled by default. The setting “TYPO3.TypoScript.enableContentCache” can be used to disable the cache explicitly. We encourage developers and integrators to leave it enabled in the Development context to spot caching issues before going into production. An integration with the file monitoring of Flow will clear the cache on code, configuration, TypoScript and template changes automatically during development

The cache is configurable via TypoScript for every path with the new “@cache” meta-property (see full changelog for more information and examples). Neos and the demo site come with a default configuration for caching. Note that caching is also supported while editing, node changes will flush the according cache segments automatically.

Some features of the TypoScript configuration

  • Entry identifiers are resolved from TypoScript using any valid value (expression, simple type or object) Content cache entries can be tagged via TS configuration
  • Neos will flush all cache entries with specific tags automatically, depending on the node that was changed (“Everything”, “Node_[Identifier]”, “NodeType_[NodeType]” or “DescendantOf_[Identifier]”)
  • A more detailed documentation and guides about this feature will follow until the final Neos 1.1 release.

General Performance Improvements

General improvements in the Flow package show faster response times and less memory consumption for all requests. On the TYPO3CR side the read access performance with many nodes was greatly increased by implementing additional indexes. The content rendering (besides the content cache) will benefit from a first level cache for many node operations (preventing duplicate queries for the same node information) and cached results during the TypoScript evaluation.

If you have implemented your own TypoScript objects, please note

  • $this->tsValue() caches the result, and behaves like a simple accessor
  • $this->tsRuntime->evaluate() will not cache the result and be evaluated every time

When moving or creating nodes the operations should be significantly faster by using DQL for batch updates, especially if many nodes are involved.

Additionally the database queries were optimised with indexes making large queries a lot faster, e.g. for rendering the tree.

Editing and User Interface

Node Tree

When a new document node is created in the node tree the content module will navigate to the new document automatically. We’ve figured out that this case is more common than creating multiple document nodes in a row. When copying or moving Nodes, they will be pasted “after” a position as the new default, before it was “into”. The new default is more consistent with the default of creating new nodes with position “after”.

The structure tree will show changed nodes (content) like the node tree does for document nodes. This gives a better overview about changes inside a document.

Node Type Switching

A feature that should have already been in the 1.0 but was postponed, is the possibility to switch an existing node to another node type. That works for document nodes as well as content nodes. The feature adds a new select box in the Inspector for node types to allow changing the current node type. If a node type is changed, all properties that are the same in the new node type will be kept.

Switch a Node Type in Neos

Node Type Switching

Asset Editor

Using arbitrary files (Assets) from the media browser for a node property was a very demanded feature from many Neos users. The new Asset Editor provides two additional property types for nodes to edit a single or multiple Assets in the inspector. The editor will be used for property types “TYPO3MediaDomainModelAsset” and “array<TYPO3MediaDomainModelAsset>” for single and multiple assignment respectively.

The new AssetList node type in the TYPO3.Neos.NodeTypes package is a simple implementation of a file list to render links to multiple Assets.

Asset editor in Neos

Asset Editor

Asset Linking

Besides editing Asset properties in the inspector there’s also the need to link to Assets from any inline editable content. An extended link plugin for Aloha allows to search for Assets by tag or title and select them in the results.

A new ConvertUris processor object is used to convert node:// and asset:// links via TypoScript. It’s already configured for the TYPO3.Neos:Content prototype, so no changes should be needed to use this feature. Linking to assets in Neos

Asset Linking

Publishing and Display of Changes

Many changes and fixes have been implemented to have a consistent state of unpublished and published changes after any action in the content module. The user interface should show a correct state after publishing or discarding changes as well as editing content or creating document nodes.

Edit and Preview

The Edit / Preview panel was improved by adding a responsive slider around the buttons in the Edit and Preview sections. This allows to place more buttons and use custom edit and preview modes extensively.

Edit and Preview

Other improvements

A new loading indicator in the content module replaces the page overlay with a spinner by a more subtle progress bar under the context bar.

Loading indicator

Neos Loading indicator The CodeMirror editor for HTML content was updated to version 3 and some annoying styling issues were fixed

The site JavaScript could break the editing UI if RequireJS was used for the website. By using a custom RequireJS context inside the Neos JavaScript this should no longer be a problem.

Content Rendering

TypoScript

The exception handling in TypoScript was improved to show the original exception if an error occurred. The ThrowingHandler exception handler implementation will just re-throw exceptions now to get a better hint about the original exception cause. The logging of exceptions in several locations was removed, so all TypoScript exception handlers have to do the actual logging themselves.

TypoScript object implementations have to implement AbstractArrayTypoScriptObject to get sub properties mapped automatically. This could be breaking for custom object implementations, note that this API is not public though.

A new BreadcrumbMenu TypoScript object was introduced in the Neos package that has item states according to Menu. The existing Breadcrumb object is deprecated now.

The Menu implementation was improved to calculate the correct entries depending on the “entryLevel” property.

Fluid

The neos:link.node and neos:uri.node view helper arguments were synchronised with the existing link view helpers from the Fluid package. The “arguments”, “section”, “addQueryString” and “argumentsToBeExcludedFromQueryString” arguments were added.

A new view helper uri.module for creating links to modules was added as an addition to the existing link.module view helper.

Eel and FlowQuery

The FlowQuery find operation added support for recursive node type or identifier queries. This allows many new exciting possibilities to query for content independent from the actual structure:

  • Find a node by identifier recursively inside the given site ${q(site).find(‘#60216562-0ad9-86ff-0b32-7b7072bcb6b2’)}
  • Find all nodes of a specific type recursively inside the given site ${q(site).find(‘[instanceof TYPO3.Neos.NodeTypes:Text]’)}

The filter operation now supports the != operator to support more situationens. Example:

titlePropertyIsNotEmpty = ${q(node).is('[title!=""'])}

The filter operation using the “instanceof” operator now works with attributes as well allowing for checking if attributes matches a certain type. Example:

imagePropertyIsImage = ${q(node).is([image instanceof TYPO3\Media\Domain\Model\ImageVariant])}

A new Math helper brings all JavaScript Math.* functions to Eel expressions. A comprehensive documentation will follow, but the MDN documentation is a good overview of the supported features.

Content Repository

Content Dimensions

The TYPO3CR got a new feature to store different variants of a node with the so called Content Dimensions. A Content Dimension is one aspect of a content variant like Localization, Personalization or Specialization for a Channel. Nodes can have multiple variants, each with one or multiple values for each dimension. The dimensions are configured via Settings (“TYPO3.TYPO3CR.contentDimensions”) and are generic, so the TYPO3CR has no concept of something like a locale. Each dimension has a default value that will be used if no specific dimension is given.

A Node migration is needed after adding a new dimension (the TYPO3CR package provides a migration with version 20140326143834 that will assign the default value of a dimension to all node variants).

The Context in TYPO3CR has a new property for the “dimensions” that will carry an ordered list of values for each dimension that acts as a fallback list when accessing content. This works completely transparent, so the application using the Context does not have to know about the actual content dimensions. All TYPO3CR operations will respect that fallback list and return the best matching variant of a Node.

Neos supports Content Dimensions in the backend by using the context path of nodes consistently. A new route part handler (experimental) can be activated to use prefixed route paths for a “locales” dimension. The Context in Neos will then be initialized to use the resolved locales fallback chain for all Node operations. The route part handler for the Neos frontend can be switched by configuring a different implementation for the TYPO3NeosRoutingFrontendNodeRoutePartHandlerInterface interface using Objects.yaml

To restrict the available locale fallback chains and give them a URL path prefix Neos comes with a new configuration for dimension presets (see “TYPO3.Neos.contentDimensions.dimensions”) that will also be used to fill the view selector that will be part of the next release.

Node Types

The node type configuration (NodeTypes.yaml) can be split in multiple files now. This is important for larger sites to have a better structure for the node type definitions. All files with the pattern “NodeTypes.*.yaml” will be used as a node type definition. The single “NodeTypes.yaml” file is still supported.

Independent

The TYPO3.TYPO3CR package had a dependency on TYPO3.Neos which has now been removed so the package can be used as a standalone package for Flow projects that would like to have the benefit of hierarchical nodes.

Other changes

  • The TYPO3CR Node implementation got support for the new CacheAwareInterface of Flow, this allows for easier caching of nodesThe Node API will emit signals (Node::NodeAdded, Node::NodeUpdated, Node::NodeRemoved) on changes to a node, this allows to create a search index over the content or react to events for other purposes
  • The ContextInterface interface was removed from the TYPO3CR package, the implementation class Context should be used instead for type hints
  • The NodeConverter does not support mapping via UUIDs anymore because they do not carry any context information (e.g. for dimensions), use node context paths instead
  • Removed the (implicit) dependency to the TYPO3.Neos package from TYPO3CR
  • The NodeConverter supports the switching of node types by an additional “_nodeType” source property
  • Node Migrations now work directly on NodeData, this could be breaking if custom Transformations or Filters were implemented
Enhancements

Removal of ExtDirect and ExtJS

The ExtJS package and usage of ExtDirect for server communication was removed in favor of plain HTTP endpoints. This is the foundation for RESTful content editing that will be a public API for Neos

The handling of the node type schema in the backend was improved to be loaded only once to reduce the number of AJAX calls.

Commands

The node type is now optional for the node:createchildnodes command.

Media

The tagging of assets via drag and drop was fixed and improved.

Breaking changes
  • Content cache

    Due to the content cache you have to specify the cache configuration for content collections and content elements rendered directly on the page. This means all secondary content collections besides the primary content and individual instantiated content objects, but not content collections inside content elements.

    Read more about the details in the documentation.

Further details can be found in the commit messages of the changes

1.2.0 (2014-12-10)

The third release of Neos focuses on adding translation support, improving the editor experience and implementing many new features. Neos is getting closer to being able to solve most project needs without custom code.

A lot of work has been put into this release to deliver a truly great user experience. Check out the online demo site (http://neos.demo.typo3.org/) for trying out the new version.

In total 94 new features, 339 tasks and 282 bugfixes made it into the beta and more non-breaking improvements will come during the finalization phase.

Upgrading from 1.1 can be done easily using the available migrations. Instructions available here http://neos.typo3.org/develop/download/upgrade-instructions-1-2.html. If you experience any issues please report them to https://jira.typo3.org/browse/NEOS.

A big thanks goes out to all the contributors that made this happen.

A bunch of teaser videos can be found here https://www.youtube.com/playlist?list=PLmMUGpq3yu-heNfu_e2HtcMH0RtaRPeJU

Translation support

Support for creating localized websites with Neos is years in the making. We took all the experience from a decade of TYPO3 CMS customer projects into account and came up with a universal concept: Content Dimensions. This feature, which is deeply rooted in Neos’ content repository, allows for creating and combining an arbitrary number of variants of a piece of content. In Neos 1.2 we use Content Dimensions for realizing translations. Once the site integrator has defined which languages should be available, an editor can translate content by simply navigating to the part of the website he’d like to translate, switch to another language and type away.

All aspects of a node – which is the technical term for any kind of content - can be translated. A new implementation of the routing component for Neos even allows for translation and customization of the URL of a particular document.

For a first impression you might want to watch a talk about multi language websites with Neos 1.2 from this year’s T3CON: http://rlmk.me/neosmulti1-2

Information about the general UI approach to localization and full use of content dimensions, some of the planned concepts are explained at http://rasmusskjoldan.com/post/82289319462/localization-is-not-about-localization

Many more features regarding content translation and content dimensions in general are on our roadmap.

See the chapter Content Dimensions for details.

Constraints

In a typical project, you will create lots of custom node types. However, many node types should only be used in a specific context and not everywhere. Using node type constraints, it is now possible to restrict the allowed child node types inside a given node type. Additionally for being able to specify direct child node constraints, it is also possible to specify grandchild constraints for auto-created node types.

See the chapter Node Type Constraints for details.

Node type constraints are supported in the following places in Neos:

  • “Create New” panel in content element handles
  • “Create New” panel in the navigate component (document and structure tree)
  • moving in Navigate component
  • changing node type in the inspector
Additional editor experience improvements
  • Link editor for nodes, assets and external links
    A link editor for the inspector that can handle internal and external links
  • Add ability to Shortcut to an external target
    Allows for linking to an external URL for shortcut pages
  • Crop aspect ratio lock presets (image editor)
    Allow locking or predefining aspect ratios for the image cropping
  • Tabs for property groups in the inspector
    Allow grouping properties and property groups across different tabs
  • Update Aloha editor
    Update to a stable version of the editor with various bugfixes and some new features
  • Improve exception handling during rendering
    Make broken pages less broken
  • Mark unpublished nodes in context structure tree
    Unpublished nodes are now highlighted in the context structure tree
  • Manual node selection in Menu element
    The menu content element now supports selecting specify menu items to show
  • Add new content element for inserting records
    New content element to insert other content elements
  • Improve usability of publishing button
    The publish button now has a active state during publishing, is disabled during saving and has become more responsive
  • Allow advanced default values for properties of type date
    Allows setting the current date and more advanced default values for date editors
  • Add icons to reference(s) inspector editor results
    The reference editor in the inspector now shows icons for the nodes
  • Allow closing dialogs with esc key
    All the different dialogs now support closing by hitting the escape key
  • Warn the user about an expired / lost session
    A login dialog appears when a session has expired allowing the editor to login again and resume work
  • Warn editors when navigating away during saving/publishing
    Warns the editor when navigating away or closing the page during saving/publishing to avoid loss of changes
  • Improve stability of content saving
    The saving of content has greatly been improved, preventing issues with content not being saved
  • Improve 404 handling in Neos backend
    When deleting the current page it would end in a 404, instead the closest parent page is found
  • Login screen removes username on failed login
    The username is kept on failed logins
  • Use correct icons for node results in Aloha link field
    Previously all results in the aloha link field had the same icon, now they have the one matching their node type
  • Use placeholder instead of default value in inline link editor
    Adds a placeholder, removes the “http://” and makes it clear that the field allows for searching
  • Improve usability of new/paste buttons in navigate component
    Adds indication that the new & paste buttons allows for altering insert/paste position
  • Sorting of node types in insert new panels
    Allows for sorting the node types in the new panels (navigate/content)
  • Login dialog improvements
    Added progress indication and streamlined normal and re-login forms.
  • Group, sort & add icons for node types in NodeTypeEditor
    Gives a better overview of available options when changing the node type.
  • Insert new panel improvements
    Options styled as cards instead of links, supports tab navigation, can handle lots of options and long labels.
Inspector features
  • Dynamically loaded options for the inspectors SelectBoxEditor
    Support for loading option values dynamically from the server
  • Multiple selection & grouping in inspector SelectBoxEditor
    Support for selecting multiple options and grouping options
  • Time support for the inspector date editor
    Allows date selectors with time selection
  • Textarea inspector editor
    An editor used for multiple lines of text in the inspector (meta description e.g.)
  • Make button label and highlighting mode configurable
    Allows for more than the HTML format for the code editor in the inspector
  • Switch to PHP date format for inspector
    The default date format for the date editor is now the PHP date format for easier usage
  • Make NodeTree baseNodeType configurable
    It’s possible to filter the node tree in a custom way to exclude unwanted document nodes
Inline editing features
  • Placeholder support for inline editable properties
    Allows for having empty inline editable properties
  • add <code> tag to Aloha Editor (disabled by default)
    Enables the use of wrapping text in a <code> tag
TypoScript features
  • TypoScript prototype to handle HTTP headers and response status
    Allows adding custom headers from TypoScript to the response (e.g. application/xml)
  • Implement TypoScript inclusion globbing
    Include multiple TypoScript files with one include line
  • @if meta property for conditional evaluation of paths
    Use conditions to disable TypoScript keys
  • NodeUri TypoScript object for linking to nodes
    A TypoScript object for making linking to nodes easier (link view helper equivalent)
  • ImageTag and ImageUri TypoScript objects
    TypoScript objects for creating images directly in TypoScript (image view helper equivalents)
  • Has FlowQuery operation
    Like the jQuery has function for filtering nodes containing specific children
  • Implement BreadcrumbMenu to replace Breadcrumb
    Breadcrumb menu streamlined with the normal menu implementation (old one deprecated)
  • Menu item attributes should have access to item in context
    The menu implementation now has access to the current item when evaluating the attributes
Backend interaction features
  • External event for node creation / removal
    Allows for updating the dom when content is created/removed in the backend
  • Expose public JavaScript API for reloading the page
    Allows for externally reloading the current page in the backend
  • External events when panels open/close and layout changes
    Events that integrators can use to update the dom when the backend panels change
Fluid features
  • Use node label for link.node view helper
    Makes it easier to link to nodes with a relative path by making the linked node accessible
  • uri.module view helper
    Equivalent of the link.module view helper
  • Allow linking to site node in NodeLinkingService
    Allows for linking to the site node with the relative path ~ in the node link view helper
Additional features
  • Dimension/Language Menu
    A new menu for linking to other dimensions (e.g. between languages) – see demo site for an example
  • Configuration module
    A new backend module to display configuration (Settings, NodeTypes, Policies, Routes, Caches, Objects, Views)
  • Introduce mixins to avoid illogical inheritance
    Multiple mixins has been added which can be reused in custom elements (TYPO3.Neos.NodeTypes:TextMixin, TYPO3.Neos.NodeTypes:ImageMixin, etc.)
  • REST services
    New REST controllers were introduced to handle various backend requests (outputs both html/json)
  • Data sources
    A new way of providing content to the backend via AJAX easily. See the chapter Data sources for details.
  • Allow simple search/replace in ChangePropertyValue transformation
    Allow node migrations to search and replace in text properties
  • Commands to activate/deactivate domains
    ./flow domain:activate & domain:deactivate
  • Handle properties of type array
    Node type properties can now be arrays (used for multiple selection in the SelectBoxEditor)
!!! Breaking changes
  • Move ImageTag and ImageUri TypoScript objects to TYPO3.Neos

    Replace all occurrences of TYPO3.Media:Image* with TYPO3.Neos:Image* to adjust your code.

  • Serialized image objects cause Doctrine errors

    Images inserted in existing sites cause fatal errors. Running ./doctrine migrate solves the issue.

  • Rename “Insert records” content element

    To adjust your existing “Insert records” nodes, run the following node migration: ./flow node:migrate 20141210114800

  • Move FlowQueryOperations concerning nodes to TYPO3CR

    Breaking if you extended existing FlowQueryOperations concerning nodes

  • Fix linking behavior

    Links to shortcut nodes now point to the end target instead of intermediary URLs

  • HTML editor: Make button label and highlighting mode configurable

    This is breaking if you used the HtmlEditor in your node types. To adjust, you need to replace HtmlEditor with CodeEditor, either manually or with ./flow core:migrate –package-key <your package>

  • Use node label for link.node view helper

    This is breaking since it changes the behavior of empty links, so if you relied on that you need to use the f:link.uri view helper inside the href attribute of a normal a tag.

  • Update Aloha editor

    b and i tags are now replaced with strong and em (old ones can still be configured).

    Now automatically adds paragraph around non formatted blocks.

    Target _blank is now added automatically to external links.

  • Harmonize TypoScript paths

    The old path Private/TypoScripts(/Library)/Root.ts2 is deprecated in favor of /Private/TypoScript/Root.ts2

  • Add ability to Shortcut to an external target

    To adjust your existing Shortcut nodes, run the following node migration: ./flow node:migrate 20140930125621

  • Switch to PHP date format for inspector date editor

    To adjust the code use the new format, it should be enough to run this on your site package(s): ./flow flow:core:migrate --package-key <sitepackagekey>

  • Deprecate unused IncludeJavaScriptViewHelper

  • Menu state should not be calculated based on a shortcut

    This is only breaking compared to the 1.1 branch not to 1.0. If you need a link to the site root page with correct active state you shouldn’t create a shortcut pointing to it but rather include the real site root in the menu, by using the itemCollection property of the Menu TypoScript object.

  • Hide document layout properties by default

    If you rely on these properties, adjust your node type configuration by setting the group on the two layout properties.

  • Change default inline editing options

    Disables the underline tag as well as sub- and super script tags by default. They can be enabled again with configuration.

  • Use strong and em instead of b and i as default

    Breaking if relying on non-native browser styling of b and i tags.

  • Mark NodeInterface::getFullLabel deprecated

    The getFullLabel method is now deprecated. The getLabel method returns the full label instead.

  • New node label management

    The code migration 20140911160326 takes care of changing existing implementations of the old NodeLabelGeneratorInterface to the deprecated NodeDataLabelGeneratorInterface and to change the NodeTypes configuration to the new format.

  • Node Migrations work on NodeData

    This is considered breaking if you added your own Transformations or Filters for Node Migrations or rely on them to only apply to a specific workspace.

  • Change handling of empty, false and null attribute values

    This will be breaking if code relied on the previous conversion of values or the output is used for XML, where the new meta property @allowEmpty should be used to disable empty attributes.

Further details can be found in the commit messages of the changes

2.0.0

Fine-grained Access Control

A common requirement, especially for larger websites with many editors, is the possibility to selectively control access to certain backend tools and parts of the content. For example so that editors can only edit certain pages or content types or that they are limited to specific workspaces. These access restrictions are used to enforce certain workflows and to reduce complexity for editors.

With Neos 2.0, we introduce a way to define Access Control Lists (ACL) in a very fine-grained manner, enabling the following use-cases:

  • hide parts of the node tree completely (useful for multi-site websites and frontend-login)
  • protect arbitrary method calls (as possible before)
  • define the visibility of arbitrary elements depending on the authenticated user (as possible before)
  • show only specific Backend Modules
  • allow to create/edit only specific Node Types
  • allow to only edit parts of the Node Tree
  • allow to only edit a specific dimension

The above examples are all based upon specific privilege types; defining what can be access-restricted.

Furthermore, the way Neos and Flow handle roles has been completely revised: A user is assigned to one or more specific roles, defining who the user is. For each role, a list of privileges is specified, defining the exact permissions of users assigned to each role.

In the Neos user interface, it is possible to assign not just a single role to a user, but instead a list of multiple roles. This allows to define the permissions a user actually has on a much more fine-grained level than before, where only the distinction between Editor and Administrator was made. Additionally, the user management module has basic support for multiple accounts per user: a user may, for example, have one account for backend access and another one for access of a member-only area on the respective website.

As an example, a privilege only giving access to a specific part of the node tree looks as follows:

'TYPO3\TYPO3CR\Security\Authorization\Privilege\Node\EditNodePrivilege':
    'YourSite:EditWebsitePart':
      matcher: 'isDescendantNodeOf("/sites/yourwebsite/custom")'
Translated Neos User Interface

The User Interface of Neos is now localized into multiple languages – making it easier to use for non-English speakers. This includes the content editing experience like Node Type definitions and editors as well as backend modules.

The preferred language can be selected in the user settings from the user menu.

If you want to translate Neos to your language or want to help improve translations, head over to http://translate.neos.io/ and start translating or find out more at https://www.neos.io/develop/translations.html.

Translation & Content Variants

While translation of content, or more broadly, content variants, are the flagship feature of Neos 1.2, there were still some missing spots to fill to make working with content variants really awesome. Neos 2.0 includes quite some of these improvements.

First, we re-implemented the way an initial translation of a document from one language to another works. If you wanted to translate from English to French in Neos 1.2, you needed to define that the French-language version of your page falls back to the “English” version – effectively showing English content if it has not been translated in French yet. With Neos 2.0, you do not need these fall-backs anymore. Instead, if you choose a content variant which does not exist yet, you are asked whether you want to start with an empty page or copy the original content and start modifying it.

Second, we re-thought how the node tree should behave in Neos: In order to reduce confusion, if you move a page to a different position in the hierarchy, it is moved in all variants. However, if you move content from left to right column, this only affects the current variant. After having tried numerous options in the last months, we believe that this way leads to the most predictable editing experience.

Third, if you copy content from one variant to another (e.g. a content element which has been created in English, but not yet in French), the link between the original content and the translation is now preserved. This is an important technical foundation, based on which features such as a “list of changes in the original language” will be implemented in later Neos releases.

Cloud-Capable Resource and Media Management

In today’s world, the use of cloud services is very prevalent. People use Google drive, Dropbox or Box.com to share files and assets. Furthermore, applications of today should be deployable on PAAS systems like Heroku or AWS EC2. Because these platforms do not contain a writable and persistent file system, alternative storage systems for assets are needed. For highly scalable websites, the use of Content Delivery Networks for serving static content helps to keep sites well performing and fast.

With Neos 2.0 and Flow 3.0, we introduce a completely written core of resource management, which features a plugin-based storage and publishing mechanism, providing support for various cloud providers and other scenarios.

On the one hand, this now allows to store persistent resources like images which the user has uploaded in Amazon S3; making Flow and Neos a lot more straightforward to run on PAAS.

On the other hand, resources which are used on the website output (like cropped and resized images) can be published to a CDN like Cloudfront, Akamai or Rackspace CloudFiles.

As a reference implementation for third-party plugins we created a package supporting Rackspace Cloudfiles. A second implementation, for Amazon S3, is about to be finished.

This feature is also the basis for seamlessly choosing assets from Google Drive or Dropbox in the Neos Media Management, which will be implemented in a later version of Neos.

SEO Improvements

With Neos 2.0, we’ve added some first tools which help in improving search engine ranks:

  • Separation of page and navigation title
  • allow to set description, keywords and robots information per-page
  • machine-readable links to alternative-language versions
  • XML sitemap generation

Furthermore, the appearance of a website when embedded inside tweets or Facebook posts can be adjusted (Open Graph).

These features are provided by a separate package https://packagist.org/packages/typo3/neos-seo

Google Analytics

For many websites, getting key insights on their usage patterns is a requirement for improving content. That’s why we created a seamless integration of Google Analytics; showing the current access numbers in an inspector tab of the current page.

Google Analytics integration for Neos 2.0 can be easily installed by adding the package https://packagist.org/packages/typo3/neos-googleanalytics

Media browser/module

The media browser has been improved in many areas.

The concept of asset collections has been introduced, which is an additional layer to separate large amounts of assets across different sites. A default asset collection can be set for a site, resulting in every asset uploaded for that site automatically being added to that collection. Asset collections can have separate tags or share tags among them.

Furthermore, searching, sorting and filtering for assets is now possible, the list view has been extended to include file size, type & thumbnail image. It is now possible to rename existing tags.

Error handling, drag and drop handling and notifications have been improved.

Editing Improvements

Searching is no longer case sensitive, including link wizards, reference(s) editors and the node tree filter.

In the editing area, the content elements toolbar now supports insert/paste before/into/after similar to the navigate component.

Image handling has been improved: Added support for SVG files. Image uploads are now possible using drag & drop in the inspector. Cropping and resizing of images can now be configured per-node type, and resizing is by default switched off to fit better with responsive websites. To enable the old behavior which allows resizing, change the following configuration in Settings.yaml:

TYPO3:
  Neos:
    userInterface:
      inspector:
        dataTypes:
          'TYPO3\Media\Domain\Model\ImageInterface':
            editorOptions:
              features:
                resize: TRUE

Furthermore, the inspector now shows detailed node information such as creation date, last modified date, last publication date, node name & identifier.

Improvements to TypoScript & Eel

There have been various finetunings in TypoScript, Eel and FlowQuery:

In order to set new variables in the TypoScript context, you had to use @override in Neos <= 1.2. We found this name is misleading, so we renamed it to @context instead, deprecating @override.

The FlowQuery operations parentsUntil, nextUntil, prevUntil, prevAll and nextAll have been introduced.

Conditions are now properly executed in processors, so you can use @if to determine whether a processor should be applied or not.

We now support nested Eel object literals such as {bar: {foo: ‘baz’}}, as well as more comparison operators (<, <=, >, >=) in FlowQuery filters.

Documentation Restructuring

The documentation has been moved to ReadTheDocs, and in this process been completely restructured. We now also provide PDF and ePub renderings of the documentation; so it is easier to search it offline.

Find the documentation at http://neos.readthedocs.org/en/2.0/index.html

Data views in inspector (experimental)

Data views is a new feature for the inspector to be able to display custom views without having a property for it.

Supports a simple view, table view and time series view to display generic data from a data source. Include D3 for SVG graphs. Currently used in the Google Analytics package.

DISCLAIMER Be aware that this feature is still experimental and likely to have breaking changes in the future.

History / Event Log (experimental)

For Neos 2.0, we have explored to add an event log, which records all kinds of changes to a Neos instance. Initially, the event log helps to answer the following questions:

  • What content has changed since I have last used the system?
  • Audit Logging: Which users have been created or modified?

A small History module is included which allows to browse the history.

By default, this feature is currently disabled, as the history grows quite quickly and there is no function to prune the history yet. We also imagine that the history can be used to enable functionality like more intelligent publishing or merging of changes.

To enable this feature (at your own “risk”), put the following configuration in Settings.yaml:

TYPO3:
  Neos:
    eventLog:
      enabled: TRUE
Additional features
  • The storage format for the node data properties table has been changed to JSON from a serialized array
    This makes it a lot easier to alter properties in the database, prevents unserialization issues and boost performance.
  • Improved exception handling with better output and styling
  • Creation date, last modified date & last publication date for nodes
  • Possibility to extend content collection as content elements
  • Auto-created child node positions (define the order of auto-created child nodes)
  • Backend context helpers (easier to determine if in the backend context)
  • Node repair improvements (remove broken nodes, remove lost nodes, remove undefined properties, add missing default values, set position)
  • Usability improvements to the sites management modules to better support multiple sites
  • Auto-created ChildNodes can now have have defined positions to define the order they appear in the backend.
!!! Breaking changes
  • Reload content without reloading the whole page
    This is breaking in case you rely on the whole page being reloaded when a property of a single node is changed. To achieve the previous behavior a new option called reloadPageIfChanged is introduced.
  • Pull in stable versions of 3rd party dependencies
    Remove the file Configuration/PackageState.php if issues occur with the Doctrine.Instantiator package.
  • Move PhpCodesniffer installation to Build folder
    See commit message for instructions.
  • Implement ContentCollection in pure TypoScript
    Change iterationName to content.iterationName to adjust existing content collections if that is used.
  • Method to easily determine if backend rendering
    Deprecates the TypoScript context variable editPreviewMode, can be replaced seamlessly with ${documentNode.context.currentRenderingMode.name} instead if used.
  • Add code migration for ImageVariant to ImageInterface change
    To adjust the code use the new class, it should be enough to run this on your site package(s): ./flow flow:core:migrate --package-key <sitepackagekey>
  • Centralized Neos user domain service
    The user:remove command has been renamed to user:delete. Additionally it drops support for the “–confirmation” option and now interactively asks for confirmation.
  • Account should not be available in the context
    This is breaking if you use the context variable ${account} in your own TypoScript. You should instead use ${Security.getAccount()} to retrieve it. Therefor you should also remove all usage of account in safed contexts for uncached TypoScript objects.
  • ContentCollection overwrites node directly
    This is breaking if you rely on the contentCollectionNode variable being set. You can retrieve the nearest ContentCollection via FlowQuery.
  • Add charset and collation to all MySQL migrations
    This is breaking if you have existing tables that do not use the utf8 charset and utf8_unicode_ci collation. To solve this you need to convert the existing tables. This can be done using the command: ./flow database:setcharset
  • Property mapper error on node properties of type date
    The code migration 20141218134700 can be run to adjust the code in your package(s): ./flow flow:core:migrate --package-key <packagekey>
  • Disable image resizing for image properties by default
    This change is breaking as the default resize feature is disabled by default now, which means you need to enable it if you rely on that feature.
  • Cleanup multi column rendering
    This is breaking if you rely on the MultiColumnItem having a template as MultiColumnItem is not a ContentCollection (so a plain tag). Attributes configured for MultiColumnItem still work as before.
  • Remove deprecated TYPO3.Neos:Page nodetype
  • Node path should always be lowercase
    This is breaking in case you have nodes with names that have uppercase letters and they are referenced by their path somewhere.
  • Minor changes to improve CR performance
    This is breaking if you rely on the fact that persists are triggered for each newly created Node. This was a side effect of assigning the highest index to the newly created Node and is now no longer needed in all cases. Therefor tests need to be adapted so that they do no longer rely on this behavior.
  • Fix unique constraint for workspace/dimensions
    This is breaking if you were unlucky enough to migrate between the merge of the the aforementioned change and this very change. See details in the commit message.
  • Node with identifier should only exist once per context
    This is breaking in case you have existing nodes in this situation, which you shouldn’t have though.
  • Throw exception for missing implementation class
    This can be breaking if relying on missing implementation classes being silenced and returning NULL.
  • Deprecate @override and replace it by @context
    The old syntax will still be supported, however you should adjust to the new syntax for streamlining.
  • Remove unused ServiceNodeController::getPageByNodePathAction

Further details can be found in the commit messages of the changes

See http://neos.readthedocs.org/en/stable/Appendixes/ChangeLogs/200.html

Note

Additionally all breaking changes in Flow 3.0 apply, see the release notes to further information. See http://flowframework.readthedocs.org/en/stable/TheDefinitiveGuide/PartV/ReleaseNotes/300.html

2.1.0

Workspaces for Editorial Teams

A major focus for Neos 2.1 have been “nested workspaces”. Workspaces allow editors to collect and review content before publishing it to the live website. Now, with nested workspaces, it is possible to stack one workspace on another and prepare larger content changes in a team. Previously it was only possible for editors to make changes in their personal workspace which would only become visible to other editors once published to the live website.

This new feature allows editors to jointly work on content for multiple content in parallel, and let all content be reviewed by our editors in charge before they are published to the live website.

Side-by-side comparison of changes in Workspace Management

This change adds a side-by-side view of changes of a given workspace to the “Review” view of the Workspace Management module. It highlights inline text changes and displays thumbnails of changed assets.

This new feature relies on a third party diff library which has been modernized and comes packaged with the Neos distribution from now on. Further details are available on Github.

Asynchronous thumbnail generation

We are introducing asynchronous thumbnail generation to Neos 2.1! This can help to avoid long backend request times when many thumbnails need to be generated and potentially allows scaling of the rendering process to multiple servers. At the same time we have reduced the number of thumbnails that need to be generated by implementing presets. This also allows thumbnails to be generated by a server-job ahead of time improving the editor experience.

Developers have numerous options to control the behaviour thumbnail generation to optimize server load and backend user experience. See the pull request on Github for all details.

Thumbnail generator strategy for advanced thumbnails

The number of thumbnails that can be generate for Neos has been greatly increased. We implemented the possibility to create thumbnails for documents such as PDF, EPS or AI files, for fonts (TTF and OTF) and for lots of image formats.

If you are a developer you get a number of methods to control how and when thumbnails are generated, shown and refreshed. Check out the pull request on Github for all the details.

Additional user interface languages

Thanks to a lot of help from our community the Neos backend is now also available in the following languages:

  • Spanish
  • Khmer
  • Portuguese (Brazilian)
  • Norwegian
  • Chinese Simplified

Head over to translate.neos.io if you can help with any translations and have a look at the information for the translation process!

2.2.0

User experience improvements
Media management improvements

Images in CMYK colorspace will be converted into RGB colorspace during the processing of images (not supported when using GD). The original image will still been kept in the original colorspace. The conversion can be disabled by setting the configuration TYPO3.Media.image.convertCMYKToRGB to false.

A new view in the media browser displays information about which nodes an asset is referenced in and where the nodes can actually be found across workspaces, content dimensions and sites.

The sorting in the media browser is now split in sort by and sort direction to sort the asset list independently.

Automatic redirects

A new optional package enables automatic redirects for renamed/moved pages. Redirects will only take effect after changes are published to the live workspace. This helps with SEO and user experience by avoiding dead links.

Additionally a 410 (gone) status code will be given for removed pages instead of 404 (not found).

Redirects can be managed via new commands:

./flow redirect:list
./flow redirect:add path/to/old-page path/to/new-page 307
./flow redirect:remove path/to/page
./flow redirect:removeall
./flow redirect:removebyhost hostname.tld

In addition redirects can be imported and exported as CSV using:

./flow redirect:export
./flow redirect:import

Redirects can only be modified using commands for the time being.

The package can be installed using composer with composer require "neos/redirecthandler-neosadapter".

Additionally a storage package needs to be installed. A default one for storing redirects in the database can be installed using composer with composer require "neos/redirecthandler-databasestorage".

Cross-site linking

Options for scheme and port have been added to site domains to enable setting them for cross-site linking. Additionally a primary flag to site domains to enable selecting them as the primary domain for a site has been added.

When linking to a node the primary domain of the site the node belongs to is taking into account. This allows for correct cross-site linking instead of creating an invalid link to a non-existing node with the existing site’s URL.

Search nodes by property & exact value in NodeDataRepository

It is no longer only possible to search through the properties by giving a string that matches for any key or value found in the jsonified properties field. Instead, the term can also be an array to match exactly on a given key / value combination. See the PR #1 for details.

Update to latest Font Awesome

Neos now ships the Font Awesome, version 4.6. This allows integrators to select from a wider range of icons for node types, inspector groups and other uses.

All icons are prefixed with “icon-” and old icon-names from version 3.2 are still available for backwards compatibility.

Documentation improvements

The documentation of Neos and Flow has been improved through a number of bugfixes and additions.

Further additions

In addition to the larger features, lots of small improvements and bugfixes have been included in Neos 2.2, among them:

See also the full release notes and changelog

!!! Breaking changes
  • Set useful defaults for Menu

    This is breaking if you rely on the previous behavior with no defaults set for the two values.

  • The demo site package is now called Neos.Demo, watch out if you somehow use the old one.

Further details can be found in the commit messages of the changes

Note

Additionally all changes in Flow 3.2 apply, see the release notes to further information. See http://flowframework.readthedocs.org/en/3.2/TheDefinitiveGuide/PartV/ReleaseNotes/320.html

2.3.0

User experience improvements
  • Stylesheets are now replaced on load of pages in backend allowing different stylesheets per page to be applied correctly. This might introduce a slight flash of unstyled content on changing pages.
  • Text editor placeholders are now translatable
  • The Neos logo in the login screen is now replaceable by configuring a different partial path for the login and overwriting the partial containing the logo.
  • The login screen has an overhauled CSS for better usability on mobile devices.
  • The content cache filters special characters used inside the cache to avoid broken cache entries. The special characters are all ascii control characters that should not appear in regular content but are sometimes introduced by copy/paste from other applications.
  • The alignment of expand icons in the node tree was corrected.
  • Select options in an inspector select editor can now
  • Switching sites is no longer error prone to session values like lastVisitedNode not lining up with the new site.
  • Cross-domain linking behavior was improved by changing internal behavior of the linking service.
  • RequireJS mapping for views is now the same as for editors, handlers and validators, allowing you to includde custom views to the inspector.
  • Node repair repairs shadow nodes, removes nodes with invalid dimensions, uses less memory and has an overall improved stability. The command also got --skip and --only options now to process the repairs in small chunks for bigger sites.
Asset and Media improvements

You can now add your own strategies to track usage of assets in your project. This is used in Neos to track usage of Assets inside content. Any AssetUsageStrategyInterface implementation that you provide will also be taken in to consideration in the Media module. Extensible Asset validation allows you to add validation to any asset class from your package, restricting the possible uploaded assets. Assets can now be replaced in the Media module, which will automatically put the new asset in place in all places the old one was used before. This works in conjunction with the asset usage strategies. The image handling supports ImageMagick 7 now, but that breaks support for some older versions.

Kickstarted sites improved

The kickstarted site now contains only the homepage, no content element anymore. Additionally the TypoScript was streamlined and improved towards extensibility.

TypoScript and EEL

The new TYPO3.Neos:ContentElementWrapping prototype can be used as a processor to the same as the contentElement.editable ViewHelper of Neos. You don’t need to do this for regular content elmeents, but for example to make properties of pages inline editable.

A TYPO3.TypoScript:Debug prototype allows to debug values inside TypoScript. You can set arbitrary key/value combinations which are output formatted.

The TYPO3.TypoScript:Collection object now has itemName set to item as default. That means you can access the current element of the collection inside the renderer via item, previously there was no default set.

The TYPO3.Neos:DimensionsMenu replaces the TYPO3.Neos:DimensionMenu (note the “s”). For backwards compatibility reasons TYPO3.Neos:DimensionMenu still works but is deprecated. The new DimensionsMenu has much more features than the old one and can be used to render dimensions in various ways.

All multi column elements now automatically provide the columnIteration variable containing iteration information and the columnLayout variable containing the selected laoyut via TypoScript context to the children (the columns).

The new sort operation (example usage: ${q(node).children().sort('title', 'DESC')}) is now available. Note that the sort is done in PHP for now, so performance for bigger datasets might decrease.

Caching changes

Objects with @cache.mode = 'cached' and no entryIdentifier set previously would use all currently assigned context variables (+ the TYPO3.TypoScript:GlobalCacheIdentifiers prototype) to build an entryIdentifier. This behavior is rather pointless as it would also use the request and possibly set backend configuration variables for example. The new behavior is to only use the GlobalIdentifiers prototype, so make sure you configure the necessary entryIdentifier variables.

Dynamic cache is a new mode for the TypoScript cache configuration. This mode will cache results but create separate cache entries based on a configured discriminator. This cache discriminator does not need to be part of the parent objects cache identifier to work (which is the case for fully cached segments). The drawback is that evaluation of this will execute a bit of PHP logic instead of pulling the cached value straight from cache. A typical example for a descriminator and dynamic cached segment is if your result is based on a request argument. See documentation for configuration examples.

Further additions

In addition to the larger features, lots of small improvements and bugfixes have been included in Neos 2.2, among them:

  • Filetype icon view helper to output icons for specific filetypes.
  • Various documentation fixes
  • General Cleanup of NodeTypes package.

See also the full release notes

!!! Breaking changes
  • Keep supertypes unset in supertypes unset

    This bugfix correctly keeps supertypes unset that are unset in a parent node type when inheriting, which was not always the case. As a result some previously (wrongly) existing configuration might now disappear.

  • Http RequestHandler returns correct instance of Request and Response

    If you used Request::createFromEnvironment() to create URLs in your custom code you must retrieve the Request object from the RequestHandler from now on. Otherwise you might run into malformed URLs like https://acme.com:80 (depending on your environment).

Note

Additionally all changes in Flow 3.3 apply, see the release notes to further information. See http://flowframework.readthedocs.org/en/3.3/TheDefinitiveGuide/PartV/ReleaseNotes/330.html

Archived Release Notes

  • 1.0.0 (2013-12-10)
  • Alpha Releases (2012-10-05 through 2013-10-30)

Release notes for unmaintained branches have been archived. To access them, look in the Release Notes appendix of the corresponding branch (or version) of the docs.

ChangeLogs

To view the ChangeLogs for other versions, check the ChangeLogs chapter in the documentation of the corresponding branch.

2.3.0 (2016-08-22)

Overview of merged pull requests
TASK: Adjust requestPattern settings to new syntax

Adjusts the requestPattern configuration to the new syntax introduced with https://github.com/neos/flow-development-collection/pull/130

TASK: Adjust unit tests to use “real mocks”

Mocking a “virtual” class is no longer allowed, so we use real classes.

  • Packages: Neos
FEATURE: node repair - remove nodes with invalid workspaces

This change introduces a new check into node:repair which scans all nodes which have null as their workspace and offers to removed them.

When workspaces have been deleted manually or users have been deleted in a non-standard way, the user’s nodes will be left behind. Because there is a constraint configured in the database between workspaces and the workspace field in Node Data, the result of such an operation will be that the respective nodes end up with null in their workspace field.

  • Packages: Neos TYPO3CR
BUGFIX: Fix error message when creating new site package

The previous error message did not say, that the format Vendor.PackageKey is mandatory.

  • Packages: Kickstarter
BUGFIX: Replace document stylesheets after loading a page

This change adds a marker class to the Neos CSS link tag and will remove and append all stylesheets into the document after loading a page in the content module. This solves issues with document dependent CSS includes on a site as well as the initial rendering of shortcut documents.

NEOS-830 #close NEOS-99 #close

  • Packages: Neos
FEATURE: Implement repair of shadow nodes

This will reconstruct missing shadow nodes in case something went wrong in creating or publishing them.

Important is to select a workspace other than live to repair as shadow nodes only appear in non base workspaces.

  • Packages: Neos TYPO3CR
BUGFIX: Shadow nodes need to be published as well

Shadow nodes were only ever deleted on publish which leads to strange results in case you publish into a workspace that has another base workspace as then the shadow node is still needed for proper function of the CR. With this change the workspace checks if the shadow node is still needed and adjusts it to the new workspace.

  • Packages: TYPO3CR
BUGFIX: Layered workspaces should retain removed nodes

In a multi-layered workspace scenario a removed node should only ever really be removed when publishing into the root workspace (live). When publishing in a workspace that has a base workspace we should instead publish a removed node into that workspace to overlay any existing nodes in the base workspace.

Additionally cleans the code as some of the checks are done deeper down again and also rely on too much internal knowledge when done in the Workspace publish methods.

NEOS-1872 #resolve

  • Packages: TYPO3CR
BUGFIX: Fix regressions introduced by skip/only change

The pull request #643 introduced two regressions where the argument order of methods was no longer correct.

  • Packages: Neos TYPO3CR
TASK: Update CreatingAPlugin.rst

correction of indentation in Routes.yaml

  • Packages: Neos
BUGFIX: `references` property type not properly converted

This results in references properties to not get wrapped with ContentElementWrappingService correctly.

Steps to reproduce: edit some property of a node of type references, hit apply, the property will become empty again.

  • Packages: Neos
BUGFIX: Fix `asset-with-metadata` endpoint for images

This adjusts the Backend\ContentController to set the CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED property mapping flag for incoming assets.

Background: When selecting a single Asset in the Neos backend, its metadata is retrieved via the /neos/content/asset-with-metadata endpoint. This expects a list of asset identifiers. However, in the case of ImageInterface-assets we instead send an object {__identity: <uuid>, __type: <type>}.

Note: The fix is backported from #102

  • Packages: Neos NodeTypes
FEATURE: Introduce –skip and –only to node:repair command

This change introduces two new options for the node:repair command which allows for selective execution of node:repair checks.

The --skip option accepts one or more check names (identifiers) which should be skipped.

If the --only option is used, only the the checks which are specified in --only will be executed.

The identifier for each check can be looked up in the node:repair help screen. If multiple check identifiers are specified, they need to be separated by commas.

  • Packages: Neos TYPO3CR
FEATURE: node:repair: remove nodes with invalid dimension values

This change contains an improvement for node:repair which runs an additional check for nodes which have dimension values which are not allowed according to the current dimension configuration.

These nodes can be either removed or the user can decide to migrate them by other means (for example a node migration).

  • Packages: TYPO3CR
BUGFIX: Escape preg_replace placeholders to prevent accidentally replacements

Escapes all $ dollar signs to prevent accidentally replacement of placeholders like $0 within the preg_replace of HtmlAugmenter.

NEOS-1865 #close

  • Packages: Neos
BUGFIX: Day incorrectly formatted in media browser

Resolves a bug that caused the month to be returned in a textual and numeric representation, by removing the months numeric representation and replacing it with the day.

  • Packages: Media
FEATURE: Dynamic cached segments

This change adds a new type of cache mode, the so called dynamic. It will always trigger a new evaluation at runtime but the results are cached again. The configuration for a dynamic segment has a new property entryDiscriminator. This defines how the cached entries for this segment are discerned from one another at runtime. Usually you will use an EEL expression, but this can only use global context variables like the request.

An example configuration for segment that is separately cached depending on a GET argument someArgument could look like this:

@cache {
    mode = 'dynamic'
    entryIdentifier {
            node = ${node}
    }
    entryDiscriminator = ${request.httpRequest.arguments.someArgument}
    context {
            1 = 'node'
    }
}
  • Packages: Neos
TASK: Free memory after disallowed child nodes removal

Free memory after removing disallowed child nodes after each dimension combination

NEOS-1852 #comment This does not the resolve the issue of much memory being used per node but prevents multiplying memory usage by the number of dimension combinations available

  • Packages: Neos TYPO3CR
BUGFIX: Fix crossdomain-linking error

The FrontendNodeRoutePartHandler caused an php error when it was called with a node that originated from another site than the site in the content context. Since a comparison between the current-node and the siteNode was used as an exit-condition for the url-path generation the method did not detect the siteNode of the external node properly and traversed up to the /sites node where an error occurred because no uri-path-segment could be found.

This fix avoids this by detecting the siteNodes by checking wether the parentPath of of the node equals SiteService::SITES_ROOT_PATH

  • Packages: Neos
BUGFIX: Correctly remove NodeDimension association in setDimensions

The setDimensions method on NodeData did simply replace the ArrayCollection with a new one. This left previously attached NodeDimension entities in the database, leading to issues.

This change fixes that by no longer replacing the full collection but working on the contained entries instead.

This fix was the base for a new task to node:repair that removes any content dimensions set on those nodes. Because when the root or the sites node have content dimensions assigned, this can lead to issues with nodes not being found when traversing from the root node.

  • Packages: Neos
BUGFIX: Site switch fails with “session not started”

This fixes a regression introduced in #591 (commit: 1fd3fcabf61f922f9019773341d74ac17b04887d) which results in an internal server error if a user tries to switch from one site to another using the Neos user interface.

The code assumed that $this->session is already the new session the tokenLoginAction is about to switch to and that this session is already initialized. However, $this->session more often than not is the session the user is about to leave and is not currently running.

The fix now unsets the lastVisitedNode in the new session the user is about to switch to and makes sure that it is fully initialized.

  • Packages: Neos
BUGFIX: node:repair also removes valid nodes

This fixes an issue with node:repair which also removes valid and healthy nodes while deleting nodes which are abstract or assigned to an unknown node type.

removeAbstractAndUndefinedNodes() correctly found invalid nodes, but only used the node path and workspace name as an identifier for removing them. If there are further nodes matching this criteria, for example with different dimension values, these would be deleted as well, even though they may be completely valid.

This patch introduces a new method which allows for removal of a node specified by node identifier and dimension hash.

  • Packages: TYPO3CR
FEATURE: ``sort()`` FlowQuery operation

Adds a sort FlowQuery operation to sort TYPO3CR nodes by given property and ASC or DESC sort order: sort(propertyName, order)

  • Packages: Neos
BUGFIX: Add message fallback for `addFlashmessage` in AssetController

Adding a flash message in AssetController results in an exception if the tranlsator service returns null for a label. If the service returns null the label will be returned as a fallback.

This change also removes an unecessary method addFlashMessage as it implements just the same logic as parent::addFlashMessage. This method also calls right now the parent method with an already translated id wich can not be translated again.

  • Packages: Media Neos
[TASK] Add trait to avoid duplicate code in ViewHelpers

The new TypoScriptContextTrait can be used to get variables from the TypoScript runtime context inside a ViewHelper as long as it’s used inside a TypoScriptAwareView. This helps to avoid code duplication while avoiding long inheritance chains.

  • Packages: Neos TYPO3CR
FEATURE: DimensionsMenu to handle multiple dimensions switching

This implements a DimensionsMenu that can render all available node variants for possible dimension combinations.

It is a drop-in replacement for the existing DimensionMenu but keeps other active dimensions in the generated links.

  • Packages: Neos
TASK: Fix code sample in content cache configuration

The path `page.content.main` is “invalid”, the missing `body` segment can be annoying when reading the documentation.

  • Packages: Neos
BUGFIX: Bust cache for content dimensions configuration

Bust the cache for content dimensions settings so changes are visible in the backend instantly.

  • Packages: Neos
TASK: `TYPO3.Neos:Menu` entryLevel should respect a starting point

If a starting point for a TYPO3.Neos:Menu is set the entryLevel won’t work out of the box in all cases because it defaults to the first level of the site. If the starting point is below that you won’t see any menu items.

This changes the default behaviour of the entryLevel. It will be set to 0 if there is a startingPoint configured otherwise stick to 1.

NEOS-1838 #resolve

  • Packages: Neos
BUGFIX: Skip private node properties in ContentElementWrappingService

If a nodetype has “virtual” properties configured (like when Elasticsearch is used with Neos), trying to access those properties resulted in

The property “…” on the subject was not accessible.

This change introduces a check for property names starting with __ and skips those, like already done in the NodePropertyConverterService

NEOS-1860 #close

  • Packages: Neos
TASK: Introduce RequireJS mapping for Views

This change introduce a mapping configuration for RequireJS for `nodeInfo.view`. With this change the configuration is mode consistent with Editors, Handlers and Validation.

  • Packages: Neos
FEATURE: Allow setting a new Node name in move operations

It would be convenient to change the name of a node while moving it to a new destination. To avoid exceptions due to existing nodes you only need to find an available name at the target location then.

  • Packages: Neos TYPO3CR
BUGFIX: Allow to change owner of workspace

This configures the property mapping when updating a workspace so that the owner can be mapped properly.

NEOS-1804 #close

  • Packages: Neos
!!! BUGFIX: Keep supertypes unset in supertypes unset

No, the title is not an error. Here is what happens:

  • You define a node type and inherit from “Document”
  • In that NodeType unset a supertype declared in “Document”
  • Now inherit from that nodetype again, and whatever the unset supertype declared, will be back

This is caused by how the inherited supertypes are read using the method getDeclaredSuperTypes, which only returns the used supertypes, not the ones not used - even if “actively not used”.

This change fixes that and is marked breaking because there might be things disappearing from your nodetypes, depending on the nesting of your hierarchy.

  • Packages: TYPO3CR
FEATURE: Make neos login-screen logo configurable

With this change it is possible to easily change the logo rendered above the login form. To do so you can adjust the partialRootPathPattern for the LoginController in your Views.yaml and include your custom logo partial

  • Packages: Neos
BUGFIX: reset lastVisitedNode on site switch

This fixes an error when trying to switch from a subnode of one site to another site.

The lastVisitedNode session variable is always pointing to the node that was last open in frontend to redirect to that page. If you visit a subpage from one site and switch to another, Neos opens the last node in the new site. In most cases this will fail.

  • Packages: Neos
BUGFIX: Make the login screen more adaptive to changes

Complete overhaul for the login screen element alignment by making use of flexible boxes. Especially smaller devices will benefit from this and everyone involved in theming the login screen. This also fixes the login screen mobile view.

  • Packages: Neos
FEATURE: Additional configuration for multi column elements

Provides the iteration information for multi column elements per default as context variable with the name columnIteration. Also provides the selected layout value of the column container to the columns via context variable named columnLayout.

  • Packages: NodeTypes
TASK: Add a hint for cache clearing to the Node Type Constraints docs

There are sometimes browser caching issues when working with node type constraints. This hint should help prevent some of them.

  • Packages: Neos
TASK: De-Duplicate site and domain logic

The logic to fetch site and domain for the ContentContext was duplicated in several parts of Neos. This duplication is rather useless as the values derived by it can be seen as default values for the two properties. Therefore the logic was refactored to the ContentContextFactory and removed from other places in favor of letting the factory set it as default.

  • Packages: Neos
BUGFIX: Fix like queries using paths in NodeDataRepository

When querying for nodes based on (parent) paths, a LIKE query was used in certain cases. This query would include unrelated nodes, if the paths involved would share a common prefix:

/some/node-12 /some/node-123

Nodes below both paths would be included because of:

LIKE “/some/nodes-12%”

Now those queries append a slash, to read:

LIKE “/some/nodes-12/%”

NEOS-1849 #close

  • Packages: TYPO3CR
BUGFIX: Add background color to select option

Add background color to select option for the electronic addresses select box, because it was white text on white background for Windows users.

NEOS-1823 #close

  • Packages: Neos
BUGFIX: Align displaced expand icons in node tree

The expand icons in the node tree where off a few pixels along the y-axis (open and folded).

NEOS-1844 #close

  • Packages: Media Neos NodeTypes
FEATURE: Allow relation between arbitrary entities and nodes

This removes all special type handling to format node properties for the Neos user interface and replaces it with using PropertyMapper. The introduced NodePropertyConverterService is fully responsible to provide a portable representation of the Node properties.

Node property types can be configured to use specific TypeConverter implementations to give all necessary information to the inspector editor. Additionally a fallback defaultValue for property types can be added in Settings.

Please note that we introduce some default values in case you didn’t set a default value in your NodeTypes.yaml. All of those are common sense but you might want to check if they work for you in all cases.

This allows to map arbitrary objects to node properties and interact with them in the Neos user interface.

NEOS-381 #close

  • Packages: Neos
BUGFIX: Include removed nodes if requested in ``filterNodeDataByBestMatchInContext``

Even when removed nodes were requested, the method looking for the best match in a context (filterNodeDataByBestMatchInContext) excluded them. This made it impossible to fetch those nodes, e.g. for publishing changes.

This change fixes that by passing on the request for removed nodes so they can be included as needed.

NEOS-1858 #close NEOS-1841 #comment Fixes regression introduced by this fix

  • Packages: TYPO3CR
BUGFIX: Check for expected context in ParentsOperation

The ParentsOperation in Neos expects a Neos ContentContext to work with, so canEvaluate() should check for it to allow for proper function and fallback handling if a “normal” CR Context is given.

  • Packages: Neos
BUGFIX: Fix resizing of images with “extreme” ratios

Images that have extreme dimensions (e.g. 2000x2) could cause exceptions when scaling because of a zero width or height when calculating the resulting thumbnail size.

This change introduces a custom Imagine Box implementation that prevents boxes with zero width or height when scaling a box.

NEOS-576 #comment PR 564 is related to this

  • Packages: Media
BUGFIX: Fix structure in ``Sites.xml`` for generated site packages

Fixes an error so freshly kickstarted site packages can be imported again

Regression of 1dcf1f2e0db3d0d7bd5f31f033be975227aa9cd0

  • Packages: Kickstarter
TASK: change caching behaviour when no `entryIdentifier` is set

The old behaviour was to try to construct the entryIdentifier from all context vars, which did not make a lot of sense.

With the new behaviour, the entryIdentifier is filled with identifiers from the TYPO3.TypoScript:GlobalCacheIdentifiers prototype.

So in many cases, it would not be necessary to provide any entryIdentifiers at all and just configure GlobalCacheIdentifiers.

  • Packages: TypoScript
TASK: set a default value of `itemName` in the `TYPO3.TypoScript:Collection` object

This change sets a default value of itemName to item, so you can use TYPO3.TypoScript:Collection object without specifying it each time:

``` helloLoop = TYPO3.TypoScript:Collection {

collection = ${[1, 2, 3]} itemRenderer = ${item + ‘<br>’}
}

This change is backwards compatible, as your value for itemName would always override the default value.

  • Packages: Neos TypoScript
BUGFIX: Protect content cache against segment tokens in content

This change adds a random cache marker directly to the content cache which will be used after cache segment tokens to add a better protection against content that contains one of these characters. The parser will only match against the cache segment tokens with added marker, so the chance of accidentally breaking the content cache should be very low.

NEOS-365 #close

  • Packages: TypoScript
TASK: Add signals to notify on asset add / update / remove

In order to implement additional tasks for asset handling, like meta data management, these new signals in the central point of asset handling - the meta data repository - notify on asset created / updated / removed.

Moved assetCreated and thumbnailCreated to the corresponding services for consistency.

  • Packages: Media Neos
BUGFIX: Add support for ImageMagick 7

ImageMagick 7 has some breaking changes and Imagick has reacted on this. Some of these changes are also breaking changes. Using ImageMagick >= 7.0 makes it mandatory to use Imagick >= 3.4.3RC1.

In case of running Neos with these versions the DocumentThumbnailGenerator throws fatal errors, because of missing class constant \Imagick::ALPHACHANNEL_RESET and missing method Imagick::flattenImages.

NEOS-1850 #close

  • Packages: Media Neos
BUGFIX: Allow the deletion of the primary domain

Currently it’s not possible to prune a site with a primary domain or delete a primary domain in the Neos backend.

This change will first unset the primary domain of a site if it’s the one which should be deleted and then deletes it.

NEOS-1839 #close

  • Packages: Neos
TASK: Fix typo in custom view helpers documentation example

There was a typo in the section about “Context and Children”. In the if block the variable $title got assigned and not checked.

  • Packages: Neos
FEATURE: ``TYPO3.TypoScript:Debug`` TypoScript-Object

A TypoScript Object “Debug” is added as an equivalent to the f:debug view helper. The Object will display the value of all child-keys in a debug window.

``` tsPath = TYPO3.TypoScript:Debug {

# optional: set title for the debug output # title = ‘Debug’

# optional: show result as plaintext # plaintext = TRUE

# If only the value-key is given it is debugged directly, # otherwise all keys except title an plaintext are debugged. value = “hello neos world”

# Additional values for debugging documentTitle = ${q(documentNode).property(‘title’)} documentPath = ${documentNode.path}

}
  • Packages: Neos TypoScript
TASK: Apply fixes from StyleCI

This pull request applies code style fixes from an analysis carried out by StyleCI.

For details see https://styleci.io/analyses/8nep21.

  • Packages: Neos TYPO3CR
TASK: Apply fixes from StyleCI

This pull request applies code style fixes from an analysis carried out by StyleCI.

For details see https://styleci.io/analyses/8LZLMk.

  • Packages: Media Neos TYPO3CR TypoScript
FEATURE: Add ``TYPO3.Neos:ContentElementEditable`` TypoScript-Object

This change extracts the functionality of the neos:contentElement.editable viewHelper into a service and adds an equivalent TypoScript-Prototype.

TypoScript Example: ``` element = TYPO3.TypoScript:Array {

title = TYPO3.TypoScript:Tag {
tagName = ‘h1’ content = ${q(node).property(‘title’)} @process.contentElementEditable = TYPO3.Neos:ContentElementEditable @process.contentElementEditable.property = ‘title’

} @process.contentElementWrapping = TYPO3.Neos:ContentElementWrapping

}
  • Packages: Media Neos
TASK: Streamline generated Site packages

Removes useless text node to prevent complications with dimensions, the breadcrumb that these days is seldom used and uses fully qualified prototype names for all used TypoScript objects to make understanding easier.

  • Packages: Kickstarter
TASK: Small code cleanup
  • Packages: Neos TYPO3CR
BUGFIX: Add autoload to composer again

In a86591d459cb9a0f87daae72839019415b6fb1a6 the autoload section was removed, as there had been no classes at that time.

  • Packages: NodeTypes
FEATURE: Use data source to list forms in inspector

Currently form identifiers need to be defined manually extending the properties of TYPO3.Neos.NodeTypes:Form . This change adds a data source which uses the TYPO3\Form\Persistence\YamlPersistenceManager::listForms to list all available forms automatically.

  • Packages: Neos NodeTypes
TASK: Cleanup NodeTypes package and templates

Removes the unnecessary AssetListImplementation and simplifies NodeType templates. Additionally sets a dependency to the form package.

  • Packages: NodeTypes
TASK: Add documentation for default TypoScript context variables

Add documentation describing how to use node, documentNode, site and request within TS

  • Packages: Neos
TASK: Small improvements for the replace asset feature
  • Unhides the action buttons in the media browser
  • Use bigger filetype icon
  • Made action names more consistent
  • Made typehinting more consistent
  • Packages: Media Neos
FEATURE: Extensible asset validation

This change allows extending the validation of assets. It is done by creating a model validator for asset entity types. The validator extends the conjunction validator and loads all validators that implement the \\TYPO3\\Media\\Domain\\Validator\AssetValidatorInterface.

  • Packages: Media
MERGE: 2.2 into master
  • Packages: Media Neos
FEATURE: Asset usage strategies

This change allows to register asset usage strategies that define if an asset is still in use and how many times.

  • Packages: Media Neos
TASK: Remove unused class imports

This change removes unused class imports throughout the neos code.

  • Packages: Kickstarter Media Neos TYPO3CR TypoScript
FEATURE: Filetype icon view helper

This change introduces a Filetype icon viewhelper that renders a simple image tag with an icon for the type of a given asset based on it’s mediatypes and given maximum dimensions.

Besides that it moves the logic for retrieving the icon to a service that can be used outside of the thumbnail generator service too.

  • Packages: Media Neos

2.3.1 (2016-08-23)

Overview of merged pull requests
BUGFIX: FileTypeIconService should have only static methods

The getDocumentIconSize method is called in getIcon which is static, therefore it should be static as well.

NEOS-1879 #resolve

  • Packages: Media Neos

2.3.10 (2017-03-01)

Overview of merged pull requests
TASK: Documentation adjustments

Adds a small example to the Eel Helpers Reference (Array.indexOf). Adds an example on how to use the help messages inside properties (Property Editor Reference).

  • Packages: Neos
TASK: Prefix `uriPathSegment` field inspector validator

I changed the non prefixed regularExpression-validator to the correct TYPO3.Neos/Validation/RegularExpressionValidator-validator

How to test

You could easily try to change the uriPathSegment on every document node type.

  • Packages: Neos
BUGFIX: Initialization of asset usage strategies

Fixes a regression introduced in https://github.com/neos/neos-development-collection/pull/1323, causing the asset usage strategies to never be initialized.

Closes #1425

  • Packages: Media Neos

2.3.11 (2017-03-10)

Overview of merged pull requests
BUGFIX: Avoid stuck tooltip in node tree

This switches (bootstrap) tooltips from being triggered on hover and focus to just hover. This avoids the tooltip being activated e.g. by expand a subtree.

Should fix #1386

  • Packages: Neos
BUGFIX: Only show remove button when image selected in ImageEditor

Do not show the “remove” button in ImageEditor when no image is selected.

  • Packages: Neos
BUGFIX: Limit VIE to predicates with custom namespace

Instead of applying VIE to all elements with [rel] or [property] attributes, only apply to those starting prefixed with the typo3 namespace.

This prevents side effects for other tags like <a href=”#” rel=”nofollow”>Link</a>.

Resolves #1449

  • Packages: Neos
BUGFIX: Add missing colons to resourcepaths in documentation

This adds missing colons to the resource paths in the examples on selecting a page template.

  • Packages: Neos
TASK: Document width and height property in ImageUri Fusion-prototype

This documents changes that were introduced in Neos 2.0 with revision 75430099fe2dbd3646eb549dac5e9778abf4c82a.

  • Packages: Neos

2.3.12 (2017-04-05)

Overview of merged pull requests
BUGFIX: Allow choice of filter for resizing images

The resize filter can have considerable impact on file size and processing power needed to do the resize, it’s therefore sensible to give the user a choice in this.

Additionally removes copying the image as that is entirely unnecessary and impacts memory usage profoundly.

  • Packages: Media Neos
BUGFIX: Use findNodesByPathPrefixAndRelatedEntities
in getRelatedNodeMethod
  • Packages: Neos
BUGFIX: Add mysql-index for the field `parentpath` in the `nodeData`-table

The find operation is currently very expensive because of an unoptimized LIKE statement. This index will to optimize the performance for find operations especially in larger cr-instances

The size of the index is a compromise between space and an assumption of the normal length of the nodePath.

  • Packages: TYPO3CR
BUGFIX: MediaModule asset edit should not fail

if no Site is defined.

How to verify it

  • delete your sites in the site management
  • got to the media browser and open an image

An exception occurres.

See: https://github.com/neos/neos-development-collection/issues/1483

  • Packages: Neos
BUGFIX: NodePropertiesStrategy in Neos should only handle site nodes

Currently the AssetUsageInNodePropertiesStrategy handles all asset references in all nodes in the node data table. The handling than is specific for nodes under the /site root node and fails when a node references an asset that is located under another root.

This fixes the issue by only selecting site nodes.

What I did Filter the nodes by site root.

How to verify it Add an asset reference to a node that is not under sites. The edit view of an asset fails.

  • Packages: Media Neos TYPO3CR
BUGFIX: Configuration reference nested twice

This causes issues with search results and creates confusion.

  • Packages: Neos
BUGFIX: Check for existing node data property works with null

The AbstractNodeData::hasProperty() method checked the existence of the given property with isset but that leads to an exception if the property has a null value. The check has been changed to array_key_exists.

Same is done in the optimization check to avoid setting existing values again in AbstractNodeData::setProperty.

Resolves #1174

  • Packages: TYPO3CR
BUGFIX: If thumbnail refresh fails, handle gracefully

If refreshing a thumbnail fails (e.g. because a PDF cannot be converted correctly), the media module dies with an exception screen.

This change catches and logs the error, and returns null as result. This leads to a missing thumbnail, but the media management stays usable.

  • Packages: Media
BUGFIX: Make layout sliding query match properly

The page layout determination in DefaultTypoScript.ts2 contains the query

q(node).parents(‘[subpageLayout]’).first().property(‘subpageLayout’)

However that immediately also matches nodes which have subpageLayout being an empty string, hence this being taken into account. This results in an empty value, even if there would be actual set layouts higher above.

The .parents() part need to be replaced with .parents(‘[subpageLayout][subpageLayout != “”]’)

Fixes #1117

  • Packages: Neos

2.3.13 (2017-06-20)

Overview of merged pull requests
BUGFIX: Use null, not empty string in Workspace->setOwner

A workspace having an owner of null (plus some other factors) is considered an internal workspace. This change makes sure the owner is set to null if an empty string is passed to setOwner().

Fixes #1610

  • Packages: TYPO3CR
BUGFIX: Nodes are inaccessible after base workspace switch

This change fixes a problem with the routing cache which results in inaccessible document nodes for cases where nodes with different identifiers but the same URI path exist in separate workspaces.

Fixes #1602

  • Packages: Neos
BUGFIX: Reset broken properties to array

If the content of the properties property cannot be decoded from JSON correctly, it will be null. This leads to errors when any operation is done that expects it to always be an array.

This change adds a PostLoad Doctrine lifecycle method to reset properties to an empty array if it is null after reconstitution.

Fixes issue #1580

  • Packages: Neos TYPO3CR
BUGFIX: Fix sample code

The sample code inside the DocBlock used the wrong view helper

  • Packages: Neos
BUGFIX: Create resource redirects correctly

The redirects for replaced resources were created using full URLs, but the redirect handler expects relative URL paths to be given.

Fixes #1573

  • Packages: Media
BUGFIX: An empty string is not rendered as a valid node name

Making sure that Utility::renderValidNodeName() actually only result in strings with length greater zero.

Fixes: #1091

  • Packages: Neos TYPO3CR
BUGFIX: Context variable `site` is available in Plugin prototype

As plugins are uncached the prototype defines which context variables will be available inside. As node, documentNode and site are defaults that apply everywhere else, the missing site variable was added to the context for consistency.

Fixes: #841

  • Packages: Neos
BUGFIX: Avoid loading original image unless cropping occurs

The image inspector used to load the full image for preview. With this change a much smaller thumbnail will be loaded instead, unless the image has been cropped or is being cropped in the cropping editor. In that case we need to load the full image to give the user a crisp preview of the selected image segment.

  • Packages: Neos
BUGFIX: Clarified doc block for LiveViewHelper

If the LiveViewHelper doesn’t get a node as argument and neither there is a node in the template variables it will always return true. The adjusted doc block clarifies that you need either.

Fixes: #1416

  • Packages: Neos
BUGFIX: Clean TypoScript of windows line-breaks

Multi-line EEL expressions fail if the TypoScript file had Windows linebreaks as the explode on line feed leaves the carriage return in every line which then stops the parser from detecting the end of a multi-line EEL expression.

  • Packages: TypoScript
BUGFIX: Fix the NodeTypes schema files and allow properties `search` and `options`

The NodeType schemas can now handle the case that a property in a NodeType definition can be either a dictionary or null.

Additionally the keys search and options as extension point for package-configuration.

The key search is used by several search implementations and currently causes validation errors. The key options is allowed to avoid such problems in the future and to create a place where packages can place custom configuration.

  • Packages: Neos TYPO3CR
BUGFIX: Allow content dimension preset translation

What I did Tranlate content dimension labels.

How I did it Just like it is already done for dimension labels

How to verify it Add content dimension. Enter translation id as label. Add id in your translation. Enjoy!

  • Packages: Neos
BUGFIX: Fix code migrations to prevent unnecessary changes

This change adjusts two code migrations (in a backwards compatible manner) so that they don’t produce invalid YAML files.

Background:

The two migrations TYPO3.TYPO3CR-130523180140 and TYPO3.Neos.NodeTypes-201309111655 both replace some “superType”/”childNode” NodeType settings. In cases where those already use the suggested format [‘<value>’ => true] this leads to invalid results ([‘<value>’ => ‘1’]). With TYPO3.TYPO3CR-20150510103823 these invalid values are fixed again, but applying all migrations lead to three unnecessary commits, possibly corrupting the configuration and/or removing important comments.

Fixes: #1351

  • Packages: NodeTypes TYPO3CR
TASK: allow to require stable version of `flow-development-collection`

This relaxes the constraints in order to be able to run stable versions of our development collections.

This is useful when you want to say use beard in production, without having to use the -dev versions.

TASK: Add tests for node name generation

Tests to prove neos/neos-development-collection#1524

  • Packages: TYPO3CR
BUGFIX: No uppercase characters allowed in node names

The changed generation of node names must avoid uppercase characters.

This is a followup to neos/neos-development-collection#1523

  • Packages: Neos TYPO3CR
TASK: Use generateRandomString() instead of uniqid()

This reduces the risk of collision on temporary names for nodes and files, as well as cache markers.

  • Packages: Media Neos TYPO3CR TypoScript
BUGFIX: Asset should return same extension as attached resource

Using the resource media type to find an extension for an asset is suboptimal because the asset knows the extension directly and the media type -> extension conversion is ambiguous so you might end up with a different extension than the resource has afterwards.

  • Packages: Media Neos
BUGFIX: Include configuration reference in TOC

The configuration reference was no longer included in the documentation TOC at all, after a recent fix aimed at no longer including it twice.

  • Packages: Neos

2.3.14 (2017-07-07)

Overview of merged pull requests
BUGFIX: Skip apply change handler if the editor is undefined

This change fix a JS console error, when ember try to call _applyChangeHandler on property like _nodeType, because this property is not really an editor.

  • Packages: Neos TYPO3CR
BUGFIX: Publish moved nodes in nested workspaces

This change contains a fix and additional Behat tests which solves an issue with moving and publishing nodes in a nested workspace scenario which can lead to data corruption in the content repository.

Resolves #1608

  • Packages: Neos TYPO3CR
BUGFIX: NodeData property exists even if set to NULL

Even if the property is set to null AbstractNodeData::hasProperty() should return true.

  • Packages: Neos TYPO3CR
BUGFIX: Detect asset://so-me-uu-id links in node properties

To detect links to assets as “usage” in the media management, the search in the NodeDataRepository is amended as needed.

Fixes #1575

  • Packages: TYPO3CR
BUGFIX: Only show link to accessible nodes

Fixed some misleading text on the listing page and added i18n.

related to #1578.

for 3.x upmerge have a look at https://github.com/ComiR/neos-development-collection/commit/e2d0e44dd6f21179b2e9eeeac1481ae3a4f8a3f6.

  • Packages: Neos
BUGFIX: render asset changes correctly in workspaces overview

This change fixes asset rendering in the workspace overview.

Fixes #1592.

  • Packages: Neos
BUGFIX: Avoid orphaned content nodes when calling publishNode()

This changes an issue with using the PublishingService::publishNode() which can result in an inconsistent structure in a user’s workspace.

This change also changes the behavior of PublishingService::discardNode() which now will also discard content of a given document node to protect consistency.

Document nodes and their content must be published or discarded together in order to protect against inconsistencies when the document node is moved or removed in one of the base workspaces.

Fixes #1617

  • Packages: Neos
BUGFIX: Behat tests fail with fresh checkout

This change fixes an issue with failing Behat tests caused by missing isolation between tests.

When certain tests were run in a specific order, they might fail with an access denied error because no user is authenticated.

Fixes #1613

  • Packages: Neos TYPO3CR

2.3.15 (2017-07-27)

Overview of merged pull requests
BUGFIX: Moving node back and forth in nested workspace causes SQL error

This change fixes a problem in the content repository which can lead to a uniqueness constraint error when a node is moved back and forth in a nested workspace.

Fixes #1639

  • Packages: TYPO3CR
BUGFIX: Prevent space if no css class is given

If no attributes.class is given the attribute always starts with space. Like that the attributes get trimmed.

### Output before: class=” foo-bar-content”

### Output after: class=”foo-bar-content”

  • Packages: Neos
BUGFIX: Valid URLs with `supportEmptySegmentForDimensions`

Makes sure that generated URLs observe the setting.

Fixes: #1644

  • Packages: Neos
BUGFIX: Trigger ContentCacheFlusher on asset update

The content cache does not invalidate on changes to an asset. Expected behavior would be to flush the content cache on changes to an asset (e.g title, caption).

Neos 2.3 PR of: https://github.com/neos/neos-development-collection/pull/1636

  • Packages: Neos TypoScript

2.3.16 (2017-08-18)

Overview of merged pull requests
BUGFIX: Build correct paths to nodes with hidden parents

If a node is visible but lies beneath a hidden parent, the URI path generated for that node had “holes” and did not work. This adjusts the route part handler to return the complete URI including the URI path segments of hidden nodes in the chain up to the site node.

To disallow showing a node actually hidden itself has to be ensured in matching a request path, not in building one.

  • Packages: Neos
BUGFIX: Allow Prototype names starting with digits

Prototype declarations starting with digits previously were wrongly parsed and resulted in broken names, this change fixes it by only casting numeric strings to integers as object keys.

Fixes: #1114

  • Packages: TypoScript
BUGFIX: TypoScriptView should set response headers correctly

The httpVersion which could be set in the ResponseHeadImplementation was not used.

Additionally, if a header had multiple values (which can easily be done in TypoScript via RawArray) only the first header was actually transferred to the sent HTTP response.

  • Packages: Neos TypoScript
BUGFIX: Fix nodetype thumbnail path in NodeTypeDefinition.rst

corrected path in documentation for thumbnail of nodetype

  • Packages: Neos
TASK: Don’t cache dynamic segments with disabled `entryDiscriminator`

With this change the caching can be disabled by setting the entryDiscriminator to false when using Content Cache mode dynamic.

Previously a cache entry was created anyways with the entryDiscriminator casted to an (in this case empty) string.

Background: The Content Cache mode dynamic was introduced in order to allow for more flexible caching behaviors depending on the context. But one important feature did not work yet: Being able to disable the cache for certain requests. With this change performance can be improved by caching the display of an interactive element (i.e. cache Forms for GET requests)

Related: #1630

  • Packages: Neos

2.3.17 (2017-11-09)

Overview of merged pull requests
BUGFIX: Avoid Request URI Too Large when loading asset metadata

When using too many assets in the inspector (AssetEditor), an error is triggered, caused by the request URI becoming too long.

This change switches the request to a POST request. The data is sent as the request body and the issue is solved.

Fixes #1747

  • Packages: Neos
BUGFIX: Shortcut nodes result in 404 if target is unavailable

A non existing (or hidden) target node would result in an infinite redirect chain but should actually result in a 404 error delivered.

Fixes: #1668

  • Packages: Neos
TASK: improve language
  • Packages: Neos TypoScript
BUGFIX: Show object in “missing template” message

The sprintf() call should only get one parameter, usage of the first one was dropped inside the message text previously.

  • Packages: TypoScript
BUGFIX: Allow cached content segments to be nested within dynamic ones

Previously when nesting content with Content Cache mode cached within segments with Content Cache mode dynamic the CONTENT_CACHE markers weren’t replaced at the second rendering.

Fixes: #1591

  • Packages: TypoScript
BUGFIX: Fix NodeType schema to pass validation

In #1678 childNodes were allowed to be nullable. But the way the schema was adjusted did not pass validation. This change fixes it.

  • Packages: Neos TYPO3CR TypoScript
BUGFIX: Allow childNode definitions to be reset

A NodeType can reset the childNode definitions of a superType by setting it to null:

```yaml ‘Some:NodeType’:

superTypes:
‘Some:Other.NodeType’: true
childNodes:
‘someChildNodes’: ~

```

But doing so lead to a schema error. This patch adjusts the schema accordingly.

  • Packages: TYPO3CR
TASK: Use interface to inject NodeSearchService in NodeController

This makes it possible to use your own implementation of the NodeSearchService.

  • Packages: Neos
BUGFIX: Register pending change must be called during editor init

This change makes sure editor listeners are called in the init of the editor. This can help in situations like hiding an editor based on depending properties on the first page load or inspector initialization.

  • Packages: Neos
TASK: Fix documentation of Debug Object

Example is missing the namespace.

  • Packages: Neos

2.3.18 (2017-11-09)

Overview of merged pull requests
BUGFIX: Assets used in moved nodes don’t break media module asset view

Prevent assets referenced in moved nodes from breaking the asset view in the media module.

Fixes #1742

  • Packages: Neos
BUGFIX: Update publish button when copying page in node tree

Make sure the publish button is updated so the new changes can be published. Additionally selects the newly copied page similar to when inserting a new document.

Resolves #914

  • Packages: Neos

2.3.19 (2017-12-15)

Overview of merged pull requests
BUGFIX: Avoid error if no dimension is set in DimensionsMenuImplementation

When using the DimensionsMenuImplementation without a set dimension (yes, there are use cases for that, e.g. hreflang tags for language _and_ country), the following could happen:

Call to a member function getLabel() on null

This change avoids that.

  • Packages: Neos
TASK: Fix border-radius on button elements

On Chrome (macOS), all <button> elements had a border-radius of 4px, which is now removed.

  • Packages: Neos
BUGFIX: Make sure nodes that are to be discarded are actually publishable

TYPO3\Neos\Service\PublishingService traverses all children of a node to discard that node recursively. Not all those nodes are actually publishable though, so the following batch discard operation fails with the Exception #1395841899: Nodes in a in a workspace without a base workspace cannot be discarded.

So, I added a filter to TYPO3\Neos\Service\PublishingService::discardNode that removes all nodes from the to-be-discarded list, that are in a different workspace than the given node.

Resolves: #1710

  • Packages: Neos
BUGFIX: Fix wrong TS path in extending pages example

Fix exception when following documentation about extending pages.

See detailed description and discussion on https://discuss.neos.io/t/1952

  • Packages: Neos
BUGFIX: ``NodePropertyConverterService`` converts default values

Apply property mapping to default value fallbacks in NodePropertyConverterService

Resolves #1781

  • Packages: Neos
TASK: Add generateUriPathSegments check identifier

This adds the generateUriPathSegments identifier to the node:repair help text.

  • Packages: Neos
BUGFIX: Long string literals should be supported in Fusion

The regex matcher would halt with a catastrophic backtracing error if a very long string was given as string literal.

  • Packages: Neos TypoScript

2.3.2 (2016-08-24)

Overview of merged pull requests

2.3.20 (2018-01-09)

Overview of merged pull requests

2.3.21 (2018-02-06)

Overview of merged pull requests
TASK: ``ReadNodePrivilege`` evaluates EEL expression only once

The ReadNodePrivilege evaluates it’s EEL evaluator twice unnecessarily, there’s some caching however it should optimize some cases.

  • Packages: Neos TYPO3CR
BUGFIX: Context structure tree only shows content

Changes the base node type filter used in the context structure tree to explicitly include content collections and content elements instead of everything that’s not a document node type.

Resolves #1784

  • Packages: Neos
BUGFIX: Let fusion render preview URIs for the Neos backend

Preview links are now generated via Fusion instead of Javascript

  • Packages: Neos
TASK: Update SPDX license identifier in composer.json
  • Packages: Kickstarter Media Neos NodeTypes TYPO3CR TypoScript
TASK: Display changes in workspaces module when setting/unsetting a DateTime values

When a DateTime property value is either set for the first time or unset the workspace module will now show that change. Previously it would only display the change if the time was set changed to a different time.

  • Packages: Neos NodeTypes

2.3.22 (2018-03-01)

Overview of merged pull requests
BUGFIX: Filtering of baseNodeType for create new dialog in trees

The “baseNodeType” filtering of allowed child node types was not implemented correctly leading to issues when using multiple allow node type filters.

Fixes: #1933

  • Packages: Neos
BUGFIX: Ensure account identifier is always added to events

For some events (e.g. copying) the account identifier is not set since it’s not initialized. Instead of doing it manually for each event type it’s done before generating an event so it’s always done.

Resolves: #1914

  • Packages: Neos
TASK: Improve history module event labels

Improves the labels by adding “the” to give it a better flow. Additionally ensures all labels are in quotation marks.

  • Packages: Neos
TASK: Remove whitespace from history module node link

Without it a space is inserted at first in the quoted link.

  • Packages: Neos
TASK: Order event log child events by their uid

Ensure that child events are ordered by their uid to ensure chronological order

  • Packages: Media Neos NodeTypes
BUGFIX: Enforce NodeTreePrivilege when filtering node tree

When using the search field or node type filter in the node tree, the NodeTreePrivilege policies aren’t taken into account.

Resolves #1867

  • Packages: Neos
BUGFIX: Fix asset references detection for nodes

This solves several issues with the implementation of asset usages

  • Can be used without logged in user (CLI)
  • Lists all references without resulting in errors
  • Speed gain if the usages are not actually needed (eg. only counted).

Gives minimal information about “inaccessible” references for now.

Also resolves #1599

  • Packages: Neos
BUGFIX: Fix VH call quote escaping in RelatedAssets.html

A call to a VH inside another VH call was not using correctly escaped single quotes, breaking parsing.

  • Packages: Neos

2.3.23 (2018-03-20)

Overview of merged pull requests
BUGFIX: Typo in WorkspaceException #1395841899

Duplicate “in a”.

  • Packages: TYPO3CR
BUGFIX: Fix asset references detection for nodes even more

Even after #1762 showing asset usage sometimes fails, with an error that can only be explained by documentNode being null when trying to render a reference.

This change adds another safety net for that case.

  • Packages: Neos
BUGFIX: Only move children with the same dimensionHash in setPath()

This changes the code in setPath() to no longer move all children across all dimension value combinations. Instead only children with the same dimensionsHash as the currently moved node will be moved along.

This avoids errors like the one described in #1696.

Fixes #1696

  • Packages: Neos TYPO3CR
BUGFIX: Dynamic cache segments not correctly re-evaluated

… Only a test to expose the wrong behavior at this point.

Fixes: #1958

  • Packages: Neos TypoScript
BUGFIX: Add null check in getOtherNodeVariants()

This avoids a fatal error in case variants of the node are not accessible for some reason.

Fixes #1896

  • Packages: TYPO3CR
TASK: Improvements to the UserInitials view helper

Improves the UserInitials view helper a bit by removing the odd dot and the end of “fullFirstName” and trims the result. Additionally strips special characters from “initials”.

  • Packages: Neos

2.3.24 (2018-05-16)

Overview of merged pull requests
TASK: Document usage of Security Context in Content Cache
  • Packages: Neos
BUGFIX: Exclude shadow nodes in findOneByIdentifier

Added a filtering for movedTo like we already do in filterNodeDataByBestMatchInContext.

See description of the discovered behavior in https://github.com/neos/neos-ui/issues/1523#issuecomment-379247165.

Closes #1986

  • Packages: TYPO3CR
BUGFIX: Dynamic cache entries should be evaluated via runtime

Dynamic cache entries are complex and need a lot of information to be evaluated correctly, therefore the runtime should always take care of this. This is potentially a bit slower than the original code but definitely more correct in outcome. Before tags were definitely wrong as they were based on the parent elements configuration.

  • Packages: Neos TypoScript
BUGFIX: Skip CSRF protection in logout action

Since we overwrite the logoutAction from Flow, we need to annotate it with @Flow\SkipCsrfProtection here too.

see neos/flow-development-collection#1014

  • Packages: Neos
TASK: Fix incorrect child node types in ``node:repair`` command

When checking for missing child nodes it doesn’t check if the existing child nodes are the correct node type. This can happen when a node has been changed to the fallback node type or if the child node type is changed in the configuration.

  • Packages: Neos TYPO3CR

2.3.25 (2018-06-06)

Overview of merged pull requests
BUGFIX: “inCacheEntryPoint” needs to be saved

It is necessary to save and restore the incacheEntryPoint state in the following situation:

  • the dynamic cache segment is evaluated in the preEvaluate step of a fusion path which will set inCacheEntryPoint to null
  • the preEvaluate returns a “cache miss” because not all segments could be replaced
  • Fusion then evaluates the path as usual
  • the runtime content cache then sets currentPathIsEntryPoint to true in enter bc inCacheEntryPoint is still null
  • the postProcess step then processes the cache entry and removes all CONTENT_CACHE markers bc currentPathIsEntryPoint is true

BTW: In this situation, uncached and dynamic segments are evaluated twice. But this is outside the scope of this bugfix. * Packages: Neos TypoScript

2.3.26 (2018-06-26)

Overview of merged pull requests
BUGFIX: Make sure to materialize as few nodes as possible

For property changes there is no necessity to materialize auto-created child nodes as well. In projects with deeply nested auto-created node structures this behaviour could quickly generate huge amounts of changed nodes therefore we should only materialize child nodes for structural changes.

All of this is only valid for workspace materializations though, in case dimensions need to be materialized as well, we need to materialize all child nodes as well for consistency.

  • Packages: Media TYPO3CR
BUGFIX: On asset change flush entries tagged with AssetDynamicTag

When using registerAssetChange() provided by ContentCacheFlusher not all affected cache entries would always be flushed. This adds flushing of entries tagged AssetDynamicTag_* as done through ConvertUrisImplementationRuntimeRuntimeContentCache to solve this.

  • Packages: Neos
BUGFIX: Prevent stale object references in user runtime cache

Holding a reference to an doctrine object can be dangerous if something happens to the UOW during that time, so that a new instance of the entity is produced, resulting in a stale entity reference that must be considered detached. We therefore should only cache the persistence identifier of a user for easier retrieval. If said user was already loaded by doctrine it will be available in the identity map and should not trigger another query, making this not less efficient than the original solution.

Additionally refactored so that the cache is flat.

  • Packages: Neos

2.3.27 (2018-08-02)

Overview of merged pull requests
TASK: Corrected description of the slice operation

Resolves issue #1322

Corresponds to PR #2113, but for Neos 2.3

  • Packages: Neos
TASK: Un-remove removed auto created child nodes in node repair

When running the createMissingChildNodes in the node:repair command, check if a child node exists but has been removed, and if so un-remove it.

  • Packages: Neos TYPO3CR

2.3.3 (2016-08-29)

Overview of merged pull requests
BUGFIX: Add translation keys to replace asset view

Replaced remaining texts with translation keys to allow translating the replace asset view.

Neos-1878 #close

  • Packages: Neos
BUGFIX: Render item label section correctly

This change fixes a wrong usage if the render- viewhelper for the dimensions menu itemLabel section

  • Packages: Neos
BUGFIX: fix sorting in Media module

Check that asset is selected before reloading the preview image.

NEOS-1882 #close

  • Packages: Neos
fix wrong hint meaning

replaces https://github.com/neos/neos-development-collection/pull/663. Now for 2.0 instead of master.

  • Packages: Neos
BUGFIX: Node property search with PostgreSQL 9.5

Adds an explicit string conversion which is needed for PostgreSQL > 9.4 to convert a JSON type to string. This is needed when matching a string pattern in the NodeSearchService against the node properties.

NEOS-1873 #resolve

  • Packages: TYPO3CR
FEATURE: Support search by property & exact value in NodeDataRepository

Currently it is only possible to search through the properties by giving a string that matches for any key or value found in the jsonified properties field.

With this change, the term can also be an array to match exactly on a given key / value combination. The search term could be given as [‘key’ => ‘value’].

NEOS-1460 #close

  • Packages: TYPO3CR

2.3.4 (2016-09-29)

Overview of merged pull requests
BUGFIX: Image upload is broken: Asset instead of ImageInterface

This fixes an issue with the Asset converter which resulted in a broken image upload function.

During the refactoring from Resource to PersistentResource, the remaining occurrences of Resource haven’t been adjusted in AssetInterfaceConverter. This didn’t lead to a direct error, but the condition where Resource was still used, could never match.

Fixes #1149

  • Packages: Media Neos
BUGFIX: Personal workspace is always deleted when user is deleted

The TYPO3.Neos:Editor role isn’t always necessary for a user to have a personal workspace.

If there doesn’t exist a workspace for that user, it will be handled in deletePersonalWorkspace() anyway.

  • Packages: Neos
BUGFIX: Check for null values after translation of FlashMessages

To make sure that after translation no null value is given as argument to parent::addFlashMessage we should prevent null values.

  • Packages: Media Neos TYPO3CR
BUGFIX: Two node publishing issues
  • Flush routing cache when a node is discarded
  • Use publishing service to publish workspace in workspaces module
  • Packages: Neos
BUGFIX: Ignore null for references property in NodeConverter

This change makes the NodeConverter accept null for references properties, a behavior also present for other property types (e.g. DateTime).

Fixes #1142

  • Packages: TYPO3CR
BUGFIX: Replace stylesheets with less side-effects

Improves the replacement of stylesheets by avoiding removing them unless actually changed between page loads. Without it a FOUC (flash of unstyled content) appears under some conditions like slow connection, device, server or similar.

Regression introduced with #375 which takes a very basic approach to solve the issue.

  • Packages: Neos
BUGFIX: Fix styling for asset details in thumbnail view

This fixes the appearance of the asset details within the media browser.

  • Packages: Neos
BUGFIX: Clickable labels in the media views

Since Fluid generates the name attribute based on the object relation, some of the fields need to be assigned a id to match their label tag.

  • Packages: Neos
BUGFIX: Prevent nesting level too deep error in checkbox view helper

To prevent a recursive comparison which can lead to this error, strict comparison is used which only compares the reference.

This issue occurs in the edit asset collection view in the media module.

  • Packages: Media
BUGFIX: Only show pointer cursor for label tags with for attribute

Instead of showing a pointer cursor for all labels, only show for those that actually have a for attribute making them clickable.

  • Packages: Neos
BUGFIX: Fix wrong Flow version in ``composer.json``

This will fix the dependency for the Flow version to correct one and prevent composer update to upgrade to unwanted minor releases.

  • Packages: Neos
BUGFIX: Make ``NodeData::createShadow`` public again

The NodeData::createShadow method was changed to protected visibility in 2.2, as it is vital to repair certain constellations of nodes it is changed back to public.

  • Packages: Neos TYPO3CR
BUGFIX: Use strict comparison in policies and UserService

This fixes potential nesting level too deep errors caused by comparing objects recursively.

  • Packages: Neos TYPO3CR
BUGFIX: createShadow cannot be called from outside as it’s protected

As this is not possible the call is replaced by code duplicated from NodeData for now.

  • Packages: Neos TYPO3CR
BUGFIX: Aloha format options

There internal selectedValue of the tag name selection for aloha get’s out of sync when changing via cursor/mouse. Since aloha already handles “changes” to same state well, no need to have this logic again.

NEOS-1883 #close

  • Packages: Neos
BUGFIX: Workspace publishing fails after node:repair

This change addresses an issue which results in a fatal error caused by foreign key constraints when a user tries to publish her changes to another workspace. The root cause is that the task in node:repair which fixes “unstable” node identifiers of auto-created child nodes only changes identifiers of nodes in a specific workspace (by default the “live” workspace) and by that irreversibly disconnects corresponding nodes in other workspaces.

The fix consists of two parts: First, the “create missing child nodes” task of node:repair is modified so that node identifiers are always changed accross all workspaces. Second, there is a new node:repair task which detects and fixes inconsistencies caused by this bug.

If you experience the symptom described earlier, simply run a node:repair to fix the inconsistencies.

The steps to reproduce the bug based on the Neos Demo site (as of August 1st, 2016) are:

  1. Log in to the backend and modify the title of the page “Forms”. Don’t publish the change yet.
  2. From the command line call node:repair and see that child node identifiers are changed.
  3. Try to publish the changes to the live workspace.

The UI will report an error which is caused by a failed SQL update. With this patch applied, the changes should be able to publish without any errors.

  • Packages: Media TYPO3CR
BUGFIX: Fix condition in `getRequestPathByNode`

First check that the node is still of type NodeInterface and until then get the parentPath.

  • Packages: Neos NodeTypes
TASK: Fixed typos in documention

@aertmann @hlubek To cleanup also the source of the content for the TS Reference.

  • Packages: Neos
TASK: RelatedNodes template need to be more solid

This change check if the relatedNode.contextDocumentNode exist before creating the link. Without this change the editor is in front of an exception.

  • Packages: Neos

2.3.5 (2016-09-29)

Overview of merged pull requests

2.3.6 (2016-09-30)

Overview of merged pull requests
BUGFIX: Undefined variable in AssetController

The upmerge from 2.2 to 2.3 introduced a regression because of an undefined variable. This was probably introduced because of a merge conflict with 427d0ed70e5365fa906f4196c936e4c9271d266e

  • Packages: Media Neos

2.3.7 (2016-10-07)

Overview of merged pull requests
BUGFIX: Re-add CSS class in edit asset view

This label class got lost during an upmerge in commit a4f1091d25f2d53a1bd31566081ef16c517d47cf.

  • Packages: Neos TYPO3CR
BUGFIX: Use up-to-date translation method in history module

Removal of TranslationHelper::translateById in Flow 3.3.4 (https://github.com/neos/flow/commit/09deb9e1e0041f20b7f3ec54af8f1fcbef92e6f0) broke the UserInitialsViewHelper and therefore the history module.

  • Packages: Neos
BUGFIX: Discard selected nodes which were moved corrupts workspace

The “discard selected nodes” feature in the Workspace Review module leaves orphaned nodes after discarding moved document nodes. The result is a seemingly empty workspace which in fact still contains nodes. The workspace can’t be deleted. The discarded document node still may appear in the Content Module’s navigation but won’t render.

Steps to reproduce based on the Neos demo site:

  • start with a clean user workspace
  • move the page Download into the page Try me
  • go to the review module (Publish Menu -> Review changes)
  • select all changes
  • press “Discard selected changes”

The document node has been removed, but the child nodes, including the corresponding shadow nodes, still exist in the database.

Closes #953

  • Packages: Neos
BUGFIX: Unpublished new nodes still have shadow nodes after removal

When an editor creates a new page and then deletes the page again, the workspace module will show pending changes because shadow nodes exist for that delete page. Because the page has never been published, Neos should just really delete the respective nodes from the user’s workspace instead of creating shadow nodes.

This change checks if a node marked for removal exists at all in one of the base workspaces and if it doesn’t, removes it completely instead of creating a shadow node.

Resolves #1163

  • Packages: TYPO3CR
TASK: Fix wrong namespaces
  • Packages: Neos TypoScript
BUGFIX: Show delete asset dialog in edit asset media view

When clicking the delete asset button in the footer of the edit asset view in the media browser/module the dialog isn’t shown due to overflow on the sticky footer is hidden. To circumvent this the dialog html is placed outside the footer.

  • Packages: Neos
BUGFIX: Return default for loadMinifiedJavaScript

If config for TYPO3.Neos.userInterface.loadMinifiedJavaScript is not set, we return TRUE as default.

  • Packages: Neos
BUGFIX: Prevent overflow issue when showing delete dialog in sites edit view

When clicking the delete site button in the sites administration module’s edit view, the following buttons jump a little due to overflow issues. This is circumvented by moving the dialog html outside of the footer.

  • Packages: Neos
TASK: Media browser fixes and improvements

Fixes and improves a bunch of different issues related to the media browser.

  • Dropdown menu overflow
  • Dropdown font size
  • Notifications not shown inside media browser (iframe)
  • Missing jQuery library when showing asset usages in media browser (iframe)
  • Clicking image thumbnail again to close leads to an error
  • Clicking image thumbnail and then usages and then cancel goes to overview instead of details
  • Clicking image thumbnail in inspector and then clicking the close button leads to an error (fixes #1135)
  • Translate labels
  • No file selected in upload / replace doesn’t display any error
  • Make “Asset in use / not in use more clear”
  • Clicking image thumbnail and then cancel goes to overview and then clicking an asset leads to an error
  • Adjust styling of asset details in thumbnail view
  • Translate flash message when deleting used asset
  • Packages: Neos
BUGFIX: Re-add ContentModule-built.js

The ContentModule-built.js has accidentally be removed during an upmerge from 2.1 to 2.2 in commit 4efb95cf46db796d2171d63279f93d970405bef8.

This change adds a recently compiled file again.

  • Packages: Neos

2.3.8 (2016-12-05)

Overview of merged pull requests
BUGFIX: Move existing live node in publish

In order to retain integrity for nodes we need to move an already existing node that is to be reused to the target path including all children. Afterwards the node can be published. That keeps child nodes together with the published parent and avoids orphan nodes. Also makes sure child nodes will not exist in two paths.

Fixes: #1277

  • Packages: TYPO3CR
BUGFIX: Show changes in ContentCollection-Nodes in review-module

This change adds the visualization of changes on TYPO3.Neos:ContentCollection nodes that also have the type TYPO3.Neos:Content to the review module.

Previously those changes were filtered out which prevented the visualization of changes and lead to the page beeing visualized as having changes without showing them in the review module.

  • Packages: Neos
TASK: Use defined version constraints in 2.3 manifests

The composer manifests for Neos 2.3 were not correctly adapted to use release versions only. Therefore installations could break after we tag stable versions of the next major as these would be pulled in by the current constraints.

This change adds the missing constraints to Neos packages to prevent that.

Fixes: #1247

  • Packages: Kickstarter Media Neos TYPO3CR TypoScript
BUGFIX: preview/edit modes share content cache

This change fixes an issue with the edit and preview modes in Neos which result in unexpected output if modes are based on the same Fusion object path.

Prior to this change, preview mode “Desktop” and the edit mode “In-Place” shared a Fusion content cache. If a site integrator wanted to react on the current mode in her Fluid template (using the {neos:rendering.inEditMode()} view helper calls) she will get wrong results, depending on which mode has been called first with an empty cache.

This change now introduces the mode identifier as a new part of the content cache identifier. Additionally, edit / preview mode buttons will now trigger a reload even for modes which are based on the same Fusion object path.

Resolves #1249

  • Packages: Neos
BUGFIX: Set default sort direction of the media browser to `DESC`

Changed sortDirection of the media browser back to DESC, so we see the most current media files in the media browser on the top.

This is a possible fix for Issue: https://github.com/neos/neos-development-collection/issues/1230 without the possibility for configuration.

  • Packages: Media
BUGFIX: Fix wrong indentations in documentation

Adjust wrong indentations in PropertyEditorReference documentation.

  • Packages: Neos
BUGFIX: Render empty `alt` attribute in ImageViewHelper

With this the ImageViewHelper will always include an alt attribute, even if not given.

Includes some namespace imports only present in 2.2 branch.

Fixes #1075

  • Packages: Media Neos TypoScript
BUGFIX: Let DateStringConverter accept ``DateTimeInterface``

This lowers the matching possibility for this specialized type converter to avoid it being used accidentally on DateTime instances instead of the Flow StringConverter.

This indirectly fixes a problem with tests exhibited in master because Flow master has a changed StringConverter that is now assigned a lower priority for DateTime objects than this converter, which is unexpected.

  • Packages: Neos
TASK: Update composer.json

This updates the composer.json in TYPO3.Neos.NodeTypes and removes the packge-key entry wich was added by mistake and also updates the root composer.json with an autogenerated version of our ComposreManifestMerger.php

  • Packages: Neos
TASK: Adjust test timezone to Africa/Tunis

The tests are currently supposed to be run in a UTC+1 timezone, due to DST we switch to a timezone that doesn’t observe DST. Africa/Tunis is a choice that fullfills these constraints.

  • Packages: Neos
TASK: Remove duplicate privilege check from NodeController

This check is already handled by policies: - TYPO3.Neos:PublicFrontendAccess - TYPO3.Neos:Backend.GeneralAccess

If that redundancy is removed it makes it possible to use the TYPO3.Neos:Backend.OtherUsersPersonalWorkspaceAccess policy to grant access to any workspace to e.g. other authenticated users. This is necessary to build a preview mechanism without an authenticated backend user to share the state of your content with external previewers.

  • Packages: Media Neos
TASK: Add warning about breaking change in 2.3

Added warning about breaking change in 2.3

  • Packages: Neos
BUGFIX: Wrong Namespace for Template in docs

It’s TYPO3.TypoScript:Template instead of TYPO3.Neos:Template

  • Packages: Neos
BUGFIX: Fix static compilation of ThumbnailGeneratorStrategy

This fixes ThumbnailGeneratorStrategy::getThumbnailGeneratorClassNames() making the method public. Without this fix, the method is silently skipped from static compilation and will always use reflection to determine classes implementing ThumbnailGeneratorInterface.

Note: With resolution of neos/flow-development-collection#662 this will prevent compilation in Production context

  • Packages: Media
TASK: Fix typo, fix path to TextFieldEditor

The path to the TextFieldEditor is missing the Inspector path part.

  • Packages: Neos
BUGFIX: Allow determination of ``ReadNodePrivilege``

Previously the ReadNodePrivilege did not implement a matchesSubject() method falling back to the default behavior of _not_ matching any subject.

Usually this is not an issue because nodes protected by this privilege will normally not be loaded anyways, but it prevents “pro-active” lookups for this privilege using the PrivilegeManager:

```

$privilegeManager->isGranted(ReadNodePrivilege::class, $node) ```

Without this fix, the above will always return FALSE.

BUGFIX: Cancel in editing user settings links to user module

Cancel in editing user settings links to user module instead of management module.

  • Packages: Neos
TASK: Remove references to typo3.org

Replaces references to typo3.org with matching references to neos.io.

  • Packages: Neos TypoScript
TASK: Apply fixes from StyleCI

This pull request applies code style fixes from an analysis carried out by StyleCI.

For details see https://styleci.io/analyses/XVBZGg.

  • Packages: Neos TYPO3CR

2.3.9 (2017-02-15)

Overview of merged pull requests
BUGFIX: Make fusion-parser aspectable

The fusion parser cloned itself previously to handle includes but to keep the defined namespaces. That made the use of aspects impossible since they were only applied on the initially created instance of the parser.

This change fixes this by using a new instance of the parser for each include and transfers the namespaces explicitly to the new parser.

  • Packages: Neos TypoScript
BUGFIX: make moving a content node across document nodes work from the tree

What I did

Moving a content node across document nodes used to give a JS error: ![image](https://cloud.githubusercontent.com/assets/837032/22254950/0ac9dd9e-e267-11e6-8d81-efe7906e4106.png)

How I did it

The error happens inside DynaTree, the code which we do not control. The only way I found to prevent it is to check for existence of child nodes before calling DynaTree’s move.

How to verify it

Cut some content node from the tree on one page and paste it on another.

  • Packages: Neos
BUGFIX: Incorrect default sort direction in media browser

Changes the default sort direction in the media browser back to descending (latest modified first).

Regression introduced in c7aed058d3a363db8e51e8e9b84a557e90bffd0e

Resolves #1230

  • Packages: Media
BUGFIX: Path parameter correctly annotated as string

For \TYPO3\TypoScript\Core\Runtime->handleRenderingException().

Fixed for 3.0 in #1389.

  • Packages: TypoScript
BUGFIX: Changing NodeType is broken

Without this change, it’s impossible to change the NodeType (from the inspector) for a NodeType with a default value for a non-scalar property (e.g. DateTime). The service tries to trim a non-scalar value, and throws an error.

This change checks if the value is a scalar before trimming and adds a check for null value.

  • Packages: TYPO3CR
BUGFIX: Set correct timezoneOffset in DateTime-picker

Fixes the bug that the DateTime-picker gets an hour off after daylight-saving-time switch.

Fixes: #851

  • Packages: Neos
BUGFIX: Remove role check when deleting workspaces for users

This was broken by 5279a7489efcd3c5f5e411b6b5bda11ad1b4ca75. Before, checks were done for the role TYPO3.Neos:Editor. However, checking for AbstractEditor is pointless; workspaces are now never deleted when a user is deleted. Since the deletePersonalWorkspace method checks for existence anyway, there’s no reason to do this role check at all. If a user is deleted, his workspaces should be deleted as well.

Fixes #1376.

  • Packages: Neos
BUGFIX: RemoveNodePrivilege blocks editing

The RemoveNodePrivilege would block editing of nodes completely, since the inspector would send all properties of a node, but the setter for “removed” was blocked by the privilege.

Now the privilege only matches on setRemoved(true) and thus only blocks what it should block.

Fixes #896

BUGFIX: Adjust exception page title

Remove “TYPO3” from error page title tag and NeosBackendMessage title tag

  • Packages: Neos
BUGFIX: Initialize usageStrategies as empty array

Currently, the Asset models of the Media package cannot be used without having an AssetUsageStrategy implemented. If no such strategy is implemented (e.g. by using Media without Neos and no need for usage information), using an Asset model will lead to a fatal error because the AssetService is trying to loop $usageStrategies which is not an empty array, but null. Therefore, $usageStrategies must be initialized as an empty array.

  • Packages: Media Neos

Indices and tables