Developer
This chapter will explain different usecases for developer working with headless
extension.
Internal Extbase plugins
To integrate a custom frontend plugin which return its data inside the JSON object, we have to do the following:
Follow the standard proceeding to register and configure extbase plugins:
Create the Demo
:
class DemoController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
public function indexAction() {
return json_encode([
'foo' => 'bar',
'settings' => $this->settings
]);
}
}
Use the plugin through TypoScript:
tt_content.list =< lib.contentElementWithHeader
tt_content.list {
fields {
content {
fields {
data = CASE
data {
key.field = list_type
demoplugin_type = USER
demoplugin_type {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
vendorName = Vendor
extensionName = ExtName
pluginName = DemoPlugin
controller = Demo
settings {
test = TEXT
test.value = The demo is working
}
}
}
}
}
}
}
Clear the cache and in the response we will see the following JSON output (shortened):
{
"content": {
"colPos0": [{
"type": "demoplugin_type",
"appearance": {...},
"content": {
"data": {
"foo": "bar",
"test": {
"value": "The demo is working",
"_typoScriptNodeValue": "TEXT"
}
}
}
}]
}
}
Integrating external plugins
The integration of other extension plugins is pretty simple. We're providing the headless_news extension as an example of how it works.
Main part is a user function definition to run a plugin from TypoScript:
tt_content.list =< lib.contentElementWithHeader
tt_content.list {
fields {
content {
fields {
data = CASE
data {
key.field = list_type
news_pi1 = USER
news_pi1 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
vendorName = GeorgRinger
extensionName = News
pluginName = Pi1
controller = News
view < plugin.tx_news.view
persistence < plugin.tx_news.persistence
settings < plugin.tx_news.settings
}
}
}
}
}
}
For any other plugin, just change the vendor
, extension
, plugin
and controller
options,
and import needed constant and setup values (like for view, persistence and settings in this case).
Than use the constants of that extension to overwrite the paths to the fluid templates:
plugin.tx_news {
view {
templateRootPath = EXT:headless_news/Resources/Private/News/Templates/
partialRootPath = EXT:headless_news/Resources/Private/News/Partials/
layoutRootPath = EXT:headless_news/Resources/Private/News/Layouts/
}
}
As last step we need to re-implement the template logic to generate JSON instead of HTML structure. We do this by creating Fluid templates at the location specified in the previous step.
Because we don't enforce any standard for the JSON structure, we are pretty free here to adjust the structure to our needs (or to the requests of our frontend developer).
Here is the shortened List.
template which generates news items into a JSON array:
<f:spaceless>
{"list": [<f:for each="{news}" as="newsItem" iteration="newsIterator">
<f:if condition="{settings.excludeAlreadyDisplayedNews}">
<f:then>
<n:format.nothing>
<n:excludeDisplayedNews newsItem="{newsItem}"/>
</n:format.nothing>
</f:then>
</f:if>
<f:render section="NewsListView" arguments="{newsItem: newsItem,settings:settings,iterator:iterator}" />
{f:if(condition: newsIterator.isLast, else: ',')}
</f:for>],
"settings":
<f:format.raw>
<f:format.json value="{
orderBy: settings.orderBy,
orderDirection: settings.orderDirection,
templateLayout: settings.templateLayout,
action: 'list'
}"/>
</f:format.raw>
}
</f:spaceless>
Create custom content elements
To add custom content elements we can straight follow the native approach of TYPO3 and fluid_styled_content.
The only difference to make it work with headless
is the configuration of the frontend template in TypoScript.
There is an overwritten content object reference in lib.
which we can use, as well as an extended
object with a header definition lib.
:
tt_content.demo >
tt_content.demo =< lib.contentElementWithHeader
tt_content.demo {
fields {
content {
fields {
demoField = TEXT
demoField.value = This is a demo content-element
bodytext = TEXT
bodytext {
field = bodytext
parseFunc =< lib.parseFunc_RTE
}
demoSubfields {
fields {
demoSubfield = TEXT
demoSubfield.value = Nested field
}
}
}
}
}
}
The definition of fields
can be nested until various depth to reflect our desired JSON structure. Also the use of
dataProcessing
is possible the native way like in any other content elements (see content element definitions of this extension).
Create custom TypoScript
To add a default TypoScript object (such as CONTENT
) to the fields of your page object you need to make sure to render it a valid JSON.
Here's an example of how you can create a JSON array of multiple objects from a custom DB table:
lib.page {
fields {
related = CONTENT
related {
table = tx_myextension_domain_model_things
select {
pidInList = this
}
renderObj = JSON
renderObj {
fields {
title = TEXT
title.field = title
link = TEXT
link.typolink.parameter.field = uid
link.typolink.returnLast = url
}
# Add recognizable token at the end of this item
stdWrap.wrap = |###BREAK###
}
stdWrap {
# Wrap items into square brackets
innerWrap = [|]
# Replace 'inner tokens' by comma, remove others
split {
token = ###BREAK###
cObjNum = 1 |*|2|*| 3
1 {
current = 1
stdWrap.wrap = |
}
2 < .1
2.stdWrap.wrap = ,|
3 < .1
}
}
}
}
}
Meta data override
Here's an example of how to override the meta object by data from a DB record:
lib.meta.stdWrap.override.cObject = JSON
lib.meta.stdWrap.override.cObject {
stdWrap.if.isTrue.data = GP:tx_news_pi1|news
dataProcessing.10 = FriendsOfTYPO3\Headless\DataProcessing\DatabaseQueryProcessor
dataProcessing.10 {
table = tx_news_domain_model_news
uidInList.data = GP:tx_news_pi1|news
uidInList.intval = 1
pidInList = 0
max = 1
as = records
fields < lib.meta.fields
fields {
title = TEXT
title.field = title
subtitle = TEXT
subtitle.field = teaser
description = TEXT
description.field = bodytext
}
returnFlattenObject = 1
}
}
EXT:form & form output decorators
EXT:headless out of box provides for developers:
Friends
Of TYPO3\ Headless\ Form\ Decorator\ Form Definition Decorator Friends
Of TYPO3\ Headless\ Form\ Decorator\ Abstract Form Definition Decorator Friends
Of TYPO3\ Headless\ Form\ Decorator\ Definition Decorator Interface
Form
is default decorator and outputs
form: {
id: "ContactForm-1",
api: {
status: null,
errors: null,
actionAfterSuccess: null,
page: {
current: 0,
nextPage: null,
pages: 1
}
},
i18n: {},
elements: []
}
You can anytime extend & customize for your needs simply by create custom
decorator which implements Definition
or extend provided
Abstract
which provides you ability to override
definition of each element or whole form definition.
After creating custom decorator you can attach to your form simply by setting
form
in rendering options of form, see more
Snippets
See issue #136