TYPO3 relation query - relational fluid rendering - typo3

I have a nested for loop in my fluid.
First for print all Parent Items.
the nested for loop should print all child elements related to the parent Item.
But the child loop dosn't work ... how should this look like?
I Have The Model Modul
and The Model Fach
and there is a 1:n Relation From Fach to Modul
And I Want to print a list like this:
Modul A
- Fach 1
- Fach 2
Modul B
- Fach ysd

For starters, if there is a relation between the objects "modules" and "fachs" there is no need to call two separate "findAll" methods. It is enougth to just call
$moduls = $this->modulRepository->findAll();
Extbase will get the relation between the two objects for you.
Your template should look like this (I don't know the property names, but you should get the context here):
<f:for each="{moduls}" as="modul">
{module.name}
<f:for each="{modul.fachs}" as="fach">
{fach.fachname}
</f:for>
</f:for>
The output of this should give the results you are looking for.
Regarding your filtering question. You should only get the data you from your database. So the best way to do this is your repository.
Depending on the kind of filtering you want to do there might be different options. But in general I would always go for the repository first. And maybe do some additional stuff after that.

fluid Code:
`<f:for each="{moduls}" as="modul">
<f:for each="{fachs}" as="fach">
{fach.fachname}
</f:for>
</f:for>`
Controller:
`public function listAction() {
$moduls = $this->modulRepository->findAll();
$fachs = $this->fachRepository->findAll();
$this->view->assign('moduls', $moduls);
$this->view->assign('fachs', $fachs);
}`
At the moment all Fach Objects were collected do I have to do the filtering with fluid or in controller?

Related

TYPO3 DCE to TYPO3FLUX

Hello guys im totally new to TYPO3 and I received a task to rewrite the DCE syntax to flux. Can anybody explain it to me how it works? do I need flux for each?
<f:for each="{dce:fal(field:'image', contentObject:contentObject)}" as="fileReference">
<vhs:resource.image identifier="{fileReference.uid}" treatIdAsReference="1" as="image1">
<vhs:variable.set name="imageSrc1" value="{image1.0.source}" />
</vhs:resource.image>
</f:for>
Actually DCE is an extension which allows you to create custom elements and you can create elements from Backend of TYPO3. Flux is a different method to create custom elements which creates elements using the viewhelpers in the template.
Here you can find the documentation of the flux https://fluidtypo3.org/documentation/templating-manual/introduction/
Both methods are different so you will need to re-create each and every element and also needs to do data entries if site is already filled with the data.

Add additional source to Image for further actions

im trying to add an additional source to the dce-image for further actions e.g. an alternate source to perform some JavaScript actions.
The wanted output should look like this:
<img src="path/to/foo.png" data-altsrc="path/to/bar.png">
The problem is the dce i'm using - its iterating through the "images" like this:
<f:for each="{dce:fal(field:'image', contentObject:contentObject)}" as="fileReference">
<f:image src="{fileReference.uid}" treatIdAsReference="1" />
</f:for>
So if I would insert multiple images to this I have no real relation between the images where i know which one is the normal-source and which one is the alternate source.
So there was the possibility to create a section and add two fields for images which we can restrict to one image per field. But there again is the for-loop which doesn't allow me to access the source of the second image for the first image.
It should be a visible relation between these images for the user which is working with the dce.
Im trying to achieve something like this:
<f:for each="{field.images}" as="images">
<!-- want to achieve something like this -->
<f:image image="{images.foo.src}" data-altsrc="{images.bar.src}">
<!-- thats the normal way iterating through images -->
<f:for each="{images.foo}" as="image">
<f:image image="{image}" />
</f:for>
</f:for>
Another idea would be to iterate first through the alternate images and store them into an array and on the main-images to access them but I have no idea if this is even possible also this will restrict the usability of the dce for the user.
Is there any way to achieve this with dce-fluid ?
Thanks in advance
Well, i guess you could extend the sys_file_reference table to add a relation from there. So you would have nested relations (never done that, so you would have to try).
You would also have to add the field to the tca type in the place you need it, that could be a little tricky. Have a look at Tca types overrides.
You could extend the sys_file_reference table with a field "alternative_reference" and add the neccessary TCA setup. Then you would have to retrieve the FileReferences via the FileRepository and use sys_file_reference as foreign table (and of course the sys_file_reference uid as identifier).
FileRepository::findByRelation(
'sys_file_reference',
'alternative_reference',
$uidOfActualSysFileReferenceRecord
);
The other possibility would be a completely new record with 2 different sys_file_reference relations. That record (eg: tx_ext_domain_model_imageset) would have an image_default and image_alternate field, both would be configured as file_relations. That would work for sure.
$defaultImages = FileRepository::findByRelation(
'tx_ext_domain_model_imageset',
'image_default',
$uidOfRecord
);
$alternativeImages = FileRepository::findByRelation(
'tx_ext_domain_model_imageset',
'image_alternative',
$uidOfRecord
);
I assume you do have knowledge about creating records, models, tca and so on.
I personally would prefer the second way, it is more clean and does not change the core-table structures.
Also there is a second image generation viewhelper, that might suite your needs better
<img src="{f:uri.image()}" data-altsrc="{f:uri.image()}" />
But the best way to go might be to write your own ViewHelper for that purpose. You could pass your Object (ImageSet) as parameter and handle all logic there. So your template would be simpler and easier to read/work on.
You have to use data attribute of fluid viewhelper and then get the uri of the image with inline call. Here is how to achieve :
<f:image src="{fileReference.uid}" data="{altsrc: '{f:uri.image(src: \'{fileReference.uid}\', treatIdAsReference: 1}" treatIdAsReference="1"/>
This should do the work.

Properties that were not listed in fluid-form overwritten after submit

In my extbase 6.2 extension (built with extension builder) I have:
An appointment that has
a lawyer that has
specializations (called expertises in this example).
In my form I simply want to edit the expertises, but every time I hit submit my lawyer's properties are emptied except for the expertises - those work, even their values are correct.
When I debug the object in fluid the lawyer is there and everything is correct.
This is the only place in my fluid form where I wrote the word "lawyer".
<f:for each="{appointment.lawyer.expertises}" as="expertise" iteration="i">
<f:form.checkbox property="lawyer.expertises.{i.index}.checked" value="1"/>
<f:for each="{expertise.subExpertises}" as="subExpertise" iteration="j">
<f:form.checkbox property="lawyer.expertises.{i.index}.subExpertises.{j.index}.checked" value="1"/>
</f:for>
</f:for>
Usually my properties of appointment don't get overwritten just because I don't write a form input-field for them.
So why are the properties of appointment.lawyer overwritten and how can I keep this from happening?
Unfortunately I have no idea what TYPO3 is doing in order to build an object from my form so any hints on that would be appreciated too :)
It is not that easy to edit the properties of related elements.
What TYPO3 does in your case is that the original related lawyer record (and also the original expertises) is detached from the appointment object and a new one is created instead, that is why you think the other properties are emptied. You will also see that, if you look up your elements in the list view, there will be more and more each time you save it. The reason is that the form is not automatically generated with the lawyer's and expertises's uids so TYPO3 thinks that these are new objects.
There is one solution I know (if someone knows a better one, please share) But you need to read the whole description:
You have to manually add the uid field in your form for every related object. Assuming that your form has name="appointment"
<f:form.hidden name="appointment[lawyer][__identity]" value="{appointment.lawyer.uid}" />
<f:form.hidden name="appointment[lawyer][expertises][{i.index}][__identity]" value="{expertise.uid}"/>
You will also have to do it for the subproperties.
Important!
That way the user can also manipulate the ids and modify the objects that he is not supposed to have access to, so you have to check the relations before saving. For that you can use the _getCleanProperty('xx') method of a domain object to get the original data of it.
if ($appointment->getLawyer()->getUid() != $appointment->_getCleanProperty('lawyer')->getUid()) {
die('error');
}
You need to check all the relations that can be manipulated that way of course.

Best way to declare content element uids to use them in fluid templates

I want to display some contentlement on every page with fluid templates. My solution was to create a typoscript element like:
lib.my.myelement= CONTENT
lib.my.myelement {
table = tt_content
select {
pidInList = 15
where = uid=99
}
}
and then use it in the fluid template with:
<f:cObject typoscriptObjectPath="lib.my.myelement" />
Another way is to create them directly in fluid with v:content.render or v:content.get. In this example I get all content elements on one page and save them in an array:
<v:variable.set name="contentElements" value="{v:content.get(column:'0', limit:'3', pageUid:'9', render:'FALSE')}" />
I can not use the first solution, cause on this page there will be much different languages ( I could use it, but every time a new language is added I would have work to declare all new uids of the new elements in typoscript).
The second solution would work better, cause when you translate a page the element uids change, but the pageUid does not change. But here I have the problem that I don't just need all elements, I also have to identify each element.
Here is how I use the second solution:
<v:variable.set name="contentElements" value="{v:content.get(column:'0', limit:'3', pageUid:'9', render:'FALSE')}" />
<f:for each="{contentElements}" as="contentElement" iteration="footerIteration">
<div class="column{v:math.sum(a: footerIteration.index, b: 1)}">
<v:content.render contentUids="{0:contentElement.uid}" />
</div>
</f:for>
As you can see, I use every element the same way.
lets create a simple case:
I have a page with the pageUid = 10 (this page will have translations). On every of this translations will be 3 elements. Lets say 1 element got the "id" (with id I mean something how I can identify this element) title1 and the other two elements have the id list1 and list2.
And my question now is How could I access for example list1?
I hope its understandable, if something is not clear please leave a comment.
Edit: I could use the same order on every translation for the elements and then check the iteration in the for-loop (see the second solution) to identify them. But I wonder if there a better, cleaner way.

TYPO3 Extbase & Fluid Grouped output with attribute from m:n relation

I'm using some domain with m:n relations in an Extbase TYPO3-Extension and want to get an output grouped by an attribute from a m:n-relation child, ideally respecting including entries having several relations.
Let's say I have Books and Categories. Books have some "title" and a "memberOfCategories" attribute, Categories have some "name" and a "areBooks" attribute. The general m:n thing (using some mn-table and the necessary fields in TCA and so on) works fine.
Using fluid, output of all categories of a book works fine, as well as all books having a certain category and so on.
But I need (in the book view / action context!) some output like that (including "duplicate" output of books belonging to more than one category):
Category A
Book A
Book B
Category B
Book A
Book C
(No Category)
Book D
Book E
I tried using the f:groupedFor ViewHelper, but that does not work as I want. Grouping by the child attribute (category.name) does not work as desired:
<f:groupedFor each="{books}" as="booksOfThisCat" groupBy="memberOfCategories.name" groupKey="memberOfCategories.name">
<h3>{memberOfCategories.name} (should be category name)</h3>
<f:for each="{booksOfThisCat}" as="book">
<li>{book.title}</li>
</f:for>
</f:groupedFor>
My first try was grouping just by memberOfCategories - but that leads to a different and unuseful result as well, because memberOfCategories only references to the "number" / set of relations, so the grouping is rubbish.
Sure that would all be very easy if I worked within an action of Categories, there it would just be a simple for each category { for each areBooks } thing, but I need that output in an action / view regarding books.
I'm pretty much sure I'm just too dumb or blind - and may have confused some readers with the slightly pidgeon English ;-), anyhow, it would be great if anybody had some hint for that. Found some similar question regarding grouping by dates, solved with a custom view helper, but I thought there might / should be an easier solution.
Oh oh - now I just got behind it on myself, it's just that simple:
Add / inject the category-Repository to my books-controller and assign its desired output (e.g. findall) to my action / view and everything is fine es it already was under the category-controller.