DCE Container Loop - typo3

I'm using the excellent DCE Extension and want to loop twice in the Container through the Child-DCEs using the fields of each Child.
In Pseudocode something like this:
Container Template:
<div id="foo">
<f:for each="{dces}" as="dce">
{dce.fields.title}
</f:for>
</div>
<div id="bar">
<f:for each="{dces}" as="dce">
{dce.fields.bla}
</f:for></div>
How can I do that?

I've solved the problem with a Viewhelper:
class DcevalViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* #param ArminVieweg\Dce\Domain\Model\Dce object
*
* #return array
*
*/
public function render($dce) {
$contentObject = $dce->getContentObject();
$temp = GeneralUtility::xml2array($contentObject['pi_flexform']);
$temp = $temp['data']['sheet.tabGeneral']['lDEF'];
foreach($temp as $key=>$val) {
preg_replace( "/\r|\n/", "", $val['vDEF'] );
$dcedata[substr($key,9)]=$val['vDEF'];
}
$dcedata['uid']=$contentObject['uid'];
return $dcedata;
}
}
And in the Containertemplate (no need for a Child template)
{namespace dce=ArminVieweg\Dce\ViewHelpers}
{namespace tom=Mediagmbh\Tomediavh\ViewHelpers}
<f:layout name="DefaultContainer" />
<f:section name="main">
<div id="foo">
<ul>
<f:for each="{dces}" as="dce">
<f:alias map="{field:'{tom:Dceval(dce:dce)}'}">
<li>{field.header}</li>
</f:alias>
</f:for>
</ul>
</div
<div id="bar">
<f:for each="{dces}" as="dce">
<f:alias map="{field:'{tom:Dceval(dce:dce)}'}">
<div><f:format.raw>{field.text}</f:format.raw></div>
</f:alias>
</f:for>
</div>
</div>
</f:section>

In DCE container definition, just use
<div id="foo">
<f:for each="{dces}" as="dce">
{dce.get.title}
</f:for>
</div>
<div id="bar">
<f:for each="{dces}" as="dce">
{dce.get.bla}
</f:for>
</div>
and nothing at all in template (2nd tab of DCE defintion).

Related

TYPO3 VHS only get image Tag

I want to get only the img tag not the whole cObject. This is what I´ve done:
<v:content.render pageUid="{this.uid}" column="5" as="tcolsid">
<f:debug>{tcolsid.0}</f:debug>
<f:format.raw>{tcolsid.0}</f:format.raw>
</v:content.render>
This is what I get:
<div id="c3" class="frame frame-default frame-type-image frame-layout-0">
<div class="ce-image ce-center ce-above">
<div class="ce-gallery" data-ce-columns="1" data-ce-images="1">
<div class="ce-outer">
<div class="ce-inner">
<div class="ce-row">
<div class="ce-column">
<figure class="image">
<img class="image-embed-item" src="fileadmin/user_upload/cappucino.jpg" width="1500" height="1101" alt=""/>
</figure>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
And i only want to get the img tag:
<img class="image-embed-item" src="fileadmin/user_upload/cappucino.jpg" width="1500" height="1101" alt=""/>
Can someone help?
Maybe something like this?
<v:content.render pageUid="23" column="0" as="records" render="false">
<f:for each="{records}" as="record">
{v:resource.record.fal(table: 'tt_content', field: 'image', uid: '{record.uid}')
-> v:iterator.first()
-> v:variable.set(name: 'image')}
<f:if condition="{image}">
<v:media.image
alt="{f:if(condition: '{image.alternative}', then: '{image.alternative}', else: '{data.header}')}"
class="d-block w-100 img-fluid" crop="{image.crop}" src="{image.uid}"
srcsetDefault="1024" treatIdAsReference="1" />
</f:if>
</f:for>
</v:content.render>

TYPO3 - Adding tx-news category to eventnews list item

I have a problem with inserting to eventnews list view data from tx-news extension - for example: category title. I have tried with this code but it didn't works:
<f:if condition="{newsItem.categories}">
<f:for each="{categories}" as="category">
<f:if condition="{category.shortcut}">
<f:then>
<f:link.page pageUid="{category.shortcut}">
{category.title}
</f:link.page>
</f:then>
<f:else>
<span>{category.title}</span>
</f:else>
</f:if>
</f:for>
</f:if>
Any suggestions how to display this data?
The whole list view template looks like that:
<f:section name="listItem">
<div class="col-md-12" style="border: 1px solid #ccc;">
<strong>
<n:link newsItem="{n}" settings="{settings}">{n.title}</n:link>
| {f:format.date(date:n.datetime.date,format:'%d.%m')}</strong>
<ul>
<f:if condition="{n.organizer}">
<li><strong>
<f:translate key="organizer" extensionName="eventnews" />
</strong>: {n.organizer.title}
<small>(uid: {n.organizer.uid})</small>
</li>
</f:if>
<f:if condition="{n.location}">
<li><strong>
<f:translate key="location" extensionName="eventnews" />
</strong>: {n.location.title}
<small>(uid: {n.location.uid})</small>
</li>
</f:if>
<f:if condition="{n.eventEnd}">
<li>
<strong>
<f:translate key="event_end" extensionName="eventnews" />
</strong>: {f:format.date(date:n.eventEnd.date,format:'%d.%m.%Y')}
</li>
</f:if>
</ul>
</div>
</f:section>

How to update 1:1 relations in Extbase

I have 2 models as below
class Communication extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
/**
* #var Filter
*/
protected $filter;
}
class Filter extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
/**
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup>
*/
protected $usergroup;
}
Template as below
<f:form class="form-horizontal" name="communication" action="update" object="{communication}">
<div class="form-group">
<label class="col-xs-3 col-md-2 control-label" for="bodytext">{f:translate(key: 'text.usergroup')}</label>
<div class="col-xs-9 col-md-10">
<f:for each="{usergroups}" as="group">
<label class="checkbox-inline">
<f:form.checkbox property="filter.usergroup" value="{group.uid}" /> {group.title}
</label>
</f:for>
</div>
</div>
<div class="form-group">
<div class="col-xs-9 col-md-10 col-xs-offset-3 col-md-offset-2">
<button type="submit" class="btn btn-primary">{f:translate(key: 'button.update')}</button>
</div>
</div>
</f:form>
When I try to update a Communication with $this->communicationRepository->update($communication), it always creates a new Filter rather than updating its own. Why this?
This is because there is no relation to the filter that is already there. For keeping the filter you need to say what id it has. I found out it works with an __identity field:
EDIT: it is probably better to wrap the field with an if condition in case there is no filter set
<f:if condition="{communication.filter.uid}">
<f:form.hidden name="communication[filter][__identity]" value="{communication.filter.uid}" />
</f:if>
Not sure, but it is possible that is also works with an uid property field:
<f:form.hidden property="filter.uid" />

Typo3 - dynamic layout

I would like create a dynamic Typo3 - Fluid layout. The width of the columns should be adjusted automatically. Through the restrictions of Fluid and Typoscript I have problems to formulate the complex condition of the center column. The AND, OR operators are not working.
I hope that somebody can help me.
Typoscript:
variables {
top < styles.content.get
top.select.where = colPos=3
left < styles.content.get
left.select.where = colPos=1
center < styles.content.get
center.select.where = colPos=0
right < styles.content.get
right.select.where = colPos=2
footer < styles.content.get
footer.select.where = colPos=4
}
Layout:
<div class="container-fluid">
TEST: {f:if(condition:'{right} AND {left}', then:'8', else:'{f:if(condition:\'{left} OR {right}\', then: \'9\', else:\'12\')}')}
<div class="row">
<div id="top_nav">
{top -> f:format.raw()}
</div>
</div>
<div class="row">
<f:if condition="{left}">
<div id="left" class="col-xs-12 col-md-{f:if(condition:'{right}', then:'2', else:'3')}">
{left -> f:format.raw()}
</div>
</f:if>
<div id="center" class="col-xs-12 col-md-{f:if(condition:'{right} AND {left}', then:'8', else:'{f:if(condition:\'{left} OR {right}\', then: \'9\', else:\'12\')}')}">
{center -> f:format.raw()}
</div>
<f:if condition="{right}">
<div id="right" class="col-xs-12 col-md-{f:if(condition:'{left}', then:'2', else:'3') }">
{right -> f:format.raw()}
</div>
</f:if>
</div>
Logical operators will only be available from TYPO3 v8
https://wiki.typo3.org/Fluid#Logical_operators
also, if you like to set a new variable (what you like to do with the class name) you could set your logic outside your html with the VHS variable set viewhelper:
https://fluidtypo3.org/viewhelpers/vhs/master/Variable/SetViewHelper.html
an example:
<f:if condition="{right}">
<f:then>
<v:variable.set name="classCenter" value="2" />
</f:then>
<f:else>
<v:variable.set name="classCenter" value="9" />
</f:else>
</f:if>
<div id="center" class="col-xs-12 col-md-{classCenter}" >
You will ofcourse need to install vhs and set the namespace in your fluid template: {namespace v=FluidTYPO3\Vhs\ViewHelpers}
That‘s just a lot of logic for template. If you decide to do it in an template try to not repeat your conditions, especially in inline notation ({f:if(…)}). I prefer using sections, be it in the same template/partial file or another, over setting variables.
Your code can get as readable as this:
<f:section="main">
<f:if condition="{right}">
<f:then>
<f:if condition="{left}">
<f:then><f:comment>left and right</f:comment>
<f:render section="top" arguments="{top:top}" />
<f:render section="left" arguments="{columns:2,left:left}" />
<f:render section="center" arguments="{columns:8,center:center}" />
<f:render section="right" arguments="{columns:2,right:right}" />
</f:then>
<f:else><f:comment>right only</f:comment>
<f:render section="top" arguments="{top:top}" />
<f:render section="center" arguments="{columns:9,center:center}" />
<f:render section="right" arguments="{columns:3,right:right}" />
</f:else>
</f:if>
</f:then>
<f:else>
<f:if condition="{left}">
<f:then><f:comment>left only</f:comment>
<f:render section="top" arguments="{top:top}" />
<f:render section="left" arguments="{columns:3,left:left}" />
<f:render section="center" arguments="{columns:9,center:center}" />
</f:then>
<f:else><f:comment>neither left nor right</f:comment>
<f:render section="top" arguments="{top:top}" />
<f:render section="center" arguments="{columns:12,center:center}" />
</f:else>
</f:if>
</f:else>
</f:if>
</f:section>
<f:section name="top">
<div class="row">
<div id="top_nav">
{top -> f:format.raw()}
</div>
</div>
</f:section>
<f:section name="left">
<div id="left" class="col-xs-12 col-md-{columns}">
{left -> f:format.raw()}
</div>
</f:section>
<f:section name="right">
<div id="right" class="col-xs-12 col-md-{columns}">
{right -> f:format.raw()}
</div>
</f:section>
<f:section name="center">
<div id="center" class="col-xs-12 col-md-{columns}">
{center -> f:format.raw()}
</div>
</f:section>
As for the condition part, IMO it‘s the maximum a fluid template should be put in. As your logic advances in complexity consider using a data processor. You can test your columns before your view‘s being rendered and assign the result to your template and use fluid layouts for your purpose.
You‘ll need some php skills for data processors. Good starting point to understand them from code ist TYPO3\CMS\Frontend\DataProcessing\CommaSeparatedValueProcessor.

TYPO3 FLUID grouping and limiting elements while looping

I'm trying to make FLuID loop which will display block with the 4 pictures. I would like to achieve something like this:
<div class="carousel-inner">
<div class="item active">
<div data-target="#carousel" data-slide-to="0" class="thumb"><img src="http://image1.jpg"></div>
<div data-target="#carousel" data-slide-to="1" class="thumb"><img src="http://image2.jpg"></div>
<div data-target="#carousel" data-slide-to="2" class="thumb"><img src="http://image3.jpg"></div>
<div data-target="#carousel" data-slide-to="3" class="thumb"><img src="http://image4.jpg"></div>
</div>
<div class="item">
<div data-target="#carousel" data-slide-to="4" class="thumb"><img src="http://image5.jpg"></div>
<div data-target="#carousel" data-slide-to="5" class="thumb"><img src="http://image6.jpg"></div>
<div data-target="#carousel" data-slide-to="6" class="thumb"><img src="http://image7.jpg"></div>
<div data-target="#carousel" data-slide-to="7" class="thumb"><img src="http://image8.jpg"></div>
</div>
</div>
The problem is that I'm newbie in FLUID stuff and don't know how to make loop with only 4 elements. My FLUID loop looks like that:
<div class="carousel-inner">
<f:for each="{paginatedAssets}" as="mediaAsset" iteration="iterator">
<f:if condition="{iterator.index} = 4">
<div class="item{f:if(condition: '{iterator.index} == 0', then: ' active')}">
<div data-target="#carousel" data-slide-to="{iterator.index}" class="thumb">
<f:render partial="MediaAsset/Detail" section="Detail" arguments="{alt:mediaAsset.alternative,title:mediaAsset.title,mediaAsset:mediaAsset,width:settings.album.thumb.width,height:settings.album.thumb.height,resizeMode:settings.album.thumb.resizeMode}" />
</div>
</div>
</f:if>
</f:for>
</div>
But it display something like that:
<div class="carousel-inner">
<div class="item active">
<div data-target="#carousel" data-slide-to="0" class="thumb">
<img title="Photo 1" alt="Photo 1" src="fileadmin/_processed_/csm_P1320323_f0d26808a1.jpg" width="800" height="600" />
</div>
</div>
<div class="item">
<div data-target="#carousel" data-slide-to="1" class="thumb">
<img title="Photo 2" alt="Photo 2" src="fileadmin/_processed_/csm_P1320326_d00a6dfa33.jpg" width="800" height="600" />
</div>
</div>
...
<div class="item">
<div data-target="#carousel" data-slide-to="n" class="thumb">
<img title="Photo n" alt="Photo n" src="fileadmin/_processed_/csm_P1234567_f001234567.jpg" width="800" height="600" />
</div>
</div>
</div>
So every loop display only one (not 4) images. Any suggestions?
I will be grateful for any help.
You can use the isFirst, isLast and cycle properties of the iterator to achieve this:
<f:for each="{paginatedAssets}" as="mediaAsset" iteration="iterator">
<f:if condition="{iterator.isFirst}">
<div class="item active">
</f:if>
<div data-target="#carousel" data-slide-to="{iterator.index}" class="thumb">
<f:render partial ... />
</div>
<f:if condition="{iterator.cycle} % 4">
<f:else>
</div>
<div class="item">
</f:else>
</f:if>
<f:if condition="{iterator.isLast}">
</div>
</f:if>
</f:for>