.. include:: ../Includes.txt .. _developer: =============== Developer =============== This chapter will explain different usecases for developer working with `headless` extension. .. _developer-plugin-extbase: 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 `DemoController.php`: .. code-block:: php 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: .. code-block:: 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): .. code-block:: json { "content": { "colPos0": [{ "type": "demoplugin_type", "appearance": {...}, "content": { "data": { "foo": "bar", "test": { "value": "The demo is working", "_typoScriptNodeValue": "TEXT" } } } }] } } .. _developer-plugin-external: 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: .. code-block:: 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 `vendorName`, `extensionName`, `pluginName` 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: .. code-block:: typoscript 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.html` template which generates news items into a JSON array: .. code-block:: html {"list": [ {f:if(condition: newsIterator.isLast, else: ',')} ], "settings": } .. _developer-custom-contentelements: 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.contentElement` which we can use, as well as an extended object with a header definition `lib.contentElementWithHeader`: .. code-block:: typoscript 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_links } 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). .. _developer-custom-typoscript: 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: .. code-block:: typoscript 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 } } } } } .. _developer-meta-override: Meta data override ================== Here's an example of how to override the meta object by data from a DB record: .. code-block:: typoscript 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 } } .. _developer-ext-form: EXT:form & form output decorators ================================= EXT:headless out of box provides for developers: - `FriendsOfTYPO3\Headless\Form\Decorator\FormDefinitionDecorator` - `FriendsOfTYPO3\Headless\Form\Decorator\AbstractFormDefinitionDecorator` - `FriendsOfTYPO3\Headless\Form\Decorator\DefinitionDecoratorInterface` `FormDefinitionDecorator` is default decorator and outputs .. code-block:: json 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 `DefinitionDecoratorInterface` or extend provided `AbstractFormDefinitionDecorator` 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 `formDecorator` in rendering options of form, :ref:`see more ` .. _developer-snippets: Snippets ======== See issue `#136 `__