How can I get the category object in Fluid of Typo3 Content Element Pictures? - typo3

after a long time of Google, I can get the categories of FAL Objects in Typo3 7.6 Fluid. But I can only return a String. I want to get an object like {data}.
What I do:
TypoScript
lib.category = CONTENT
lib.category {
table=sys_category
wrap=|
select {
pidInList = root,0,1
recursive = 99
max=10
selectFields=sys_category.title,sys_category.uid
join = sys_category_record_mm on sys_category_record_mm.uid_local = sys_category.uid join sys_file_metadata on sys_file_metadata.uid = sys_category_record_mm.uid_foreign join sys_file_reference on sys_file_reference.uid_local = sys_file_metadata.file
where.field = fuid
where.wrap = sys_file_reference.uid=|
}
renderObj=COA
renderObj {
1=TEXT
1.field = uid
2=TEXT
2.field = title
}
}
In Fluid I have:
<f:for each="{files}" as="file">
<p>
- {file.uid}<br />
- <f:cObject typoscriptObjectPath="lib.category" data="{fuid:file.uid}" />
</p>
</f:for>
On the webpage it prints:
88
3Black7Small
89
2Blue7Big
90
1Red
But I think an object in Fluid is better, so I can use f:for each etc. But I don't know how I can return it.
Can anybody help me?

Looks like this task is very tricky. The file object in the {files} array is of type \TYPO3\CMS\Core\Resource\FileReference where properties like uid, title or description are passed through from the original file object of type \TYPO3\CMS\Core\Resource\File. FileReference is actually implemented as a model but not file, so you can not extend it.
The only other way i see is to create a viewhelper that will get the categories with a native sql query and the CategoryRepository would automatically map the result to the Category model. Something like that:
<?php
namespace Vendor\Extension\ViewHelpers;
/**
*
* #version $Id$
* #copyright Dimitri Lavrenuek <lavrenuek.de>
* #license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 or later
*/
class GetFileCategoriesViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* #var \TYPO3\CMS\Extbase\Domain\Repository\CategoryRepository
* #inject
*/
protected $categoryRepository;
/**
* #param int $uid
* #return array
*/
public function render ($uid) {
$query = $this->categoryRepository->createQuery();
$sql = "SELECT sys_category.* FROM sys_category
INNER JOIN sys_category_record_mm ON sys_category_record_mm.uid_local = sys_category.uid AND sys_category_record_mm.fieldname = 'categories' AND sys_category_record_mm.tablenames = 'sys_file_metadata'
INNER JOIN sys_file_metadata ON sys_category_record_mm.uid_foreign = sys_file_metadata.uid
WHERE sys_file_metadata.file = '" . (int)$uid . "'
AND sys_category.deleted = 0
ORDER BY sys_category_record_mm.sorting_foreign ASC";
return $query->statement($sql)->execute();
}
}
I have not tested the actual code, only the sql query, but this should work. Also i hope that you know how to include viewhelpers in your fluid template, if not I will provide an example.

Related

Why are my typolinks t3: not replaced if I fetch them with CONTENT?

I have Typoscript like this:
lib.rccProcessTexts = CONTENT
lib.rccProcessTexts {
table = tt_content
select {
pidInList = {$rcc.ids.pidRccProcessTexts}
}
renderObj = COA
renderObj {
10 = TEXT
# The field tt_content.bodytext holds the content text.
10.stdWrap.field = bodytext
10.stdWrap.wrap = <div data-phase-id="{field:colPos}">|</div>
10.insertData = 1
}
wrap = <div class="hidden" data-process-texts>|</div>
}
So this Typoscript fetches content from tt_content. Any typolinks (t3://...) are not replaced by real links (like https://www.example.com/go/to/page).
How can I make TYPO3 create real links?
You have 2 possibilities.
is documented here: https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/ContentObjects/Text/Index.html
It is to add this parseFunc to the TEXT object:
10.stdWrap.parseFunc < lib.parseFunc_RTE
This will cause the text to be parsed as usual.
So finally:
...
...
renderObj = COA
renderObj {
10 = TEXT
# The field tt_content.bodytext holds the content text.
10.stdWrap.field = bodytext
10.stdWrap.wrap = <div data-phase-id="{field:colPos}">|</div>
10.insertData = 1
10.stdWrap.parseFunc < lib.parseFunc_RTE
}
...
The second is to write a userfunc with PHP.
10.stdWrap.parseFunc.userFunc = My\Way\To\MyClass.php->doSomething()
Then just add Class.php with doSomething() to the Classes/UserFunc folder. The class is like so:
<?php
namespace My\Way\To;
class MyClass
{
/**
* #var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
public $cObj;
/**
*
* #param string When custom methods are used for data processing (like in stdWrap functions), the $content variable will hold the value to be processed. When methods are meant to just return some generated content (like in USER and USER_INT objects), this variable is empty.
* #param array TypoScript properties passed to this method.
* #return string The input string reversed. If the TypoScript property "uppercase" was set, it will also be in uppercase. May also be linked.
*/
public function doSomething(string $content, array $conf): string
{
// Have fun
}
}

Is there a way to search in Extbase and the TYPO3 query builder for words which have a "&shy" inside?

I have the problem that the backend users can set a word with a "­" character, for example something like "Test&shy ;labor".
If someone uses the frontend search with the word "Testlabor" no match will be found.
In the extbase repository I used this:
$query->like('name', '%' . $searchWord . '%')
I can change that to something like this:
$query->statement("SELECT * FROM table WHERE hidden = 0 AND REPLACE(name,'­', '') LIKE '%$searchWord%'")
Then the word will be found but I have to check all the things the framework normally does, like check if it's hidden and deleted and more complicated, if the result is in the right site tree. Now I just get everything that matches the searchword.
Is there a better way to search for words which have "­" inside? Can I use something like that within the TYPO3 query builder?
Many thanks in advance.
You can try with QueryBuilder interface
public function findShy($searchWord)
{
/** #var ConnectionPool $pool */
$pool = GeneralUtility::makeInstance(ConnectionPool::class);
$connection = $pool->getConnectionForTable('table');
$queryBuilder = $connection->createQueryBuilder();
$query = $queryBuilder
->select('*')
->from('table')
->where("REPLACE(name,'­', '') like :name")
->setParameter('name', "%{$searchWord}%");
// for debug only
echo($query->getSQL());
print_r($query->getParameters());
return $query->execute()->fetchAll();
}
and call it somewhere i.e. in your controller:
DebuggerUtility::var_dump(
$this->yourRepository->findShy('Testlabor'),
'findShy() sample'
);
it will create a query with named parameter like (according to your TCA of course):
SELECT *
FROM `table`
WHERE (REPLACE(name, '­'­, '') like :name)
AND ((`table`.`deleted` = 0) AND (`table`.`hidden` = 0) AND
(`table`.`starttime` <= 1596363840) AND
((`table`.`endtime` = 0) OR (`table`.`endtime` > 1596363840)))
Note that returns associative array with the record not a mapped object of your model.
Optional
If you need mapped model objects anyway, you can mix these two solutions, i.e. first select only the pids of your records with QueryBuilder and then fetch them with Query which implements QueryInterface like this:
public function findShy2($searchWord)
{
/** #var ConnectionPool $pool */
$pool = GeneralUtility::makeInstance(ConnectionPool::class);
$connection = $pool->getConnectionForTable('table');
$queryBuilder = $connection->createQueryBuilder();
$preQuery = $queryBuilder
->select('uid')
->from('table')
->where("REPLACE(name,'­', '') like :name")
->setParameter('name', "%{$searchWord}%");
// for debug only
echo($query->getSQL());
print_r($query->getParameters());
$uids = [];
foreach ($preQuery->execute()->fetchAll() as $item) {
$uids[] = $item['uid'];
}
if(count($uids) > 0){
$interfaceQuery = $this->createQuery();
$interfaceQuery->matching(
$interfaceQuery->in('uid', $uids)
);
return $interfaceQuery->execute();
}
return [];
}

How do I get uid of a File Reference Object in TYPO3?

I am trying to get a file through this code $f = $resourceFactory->getFileObject($uid); but the problem is the uid is a protected field in the file reference object, as seen below so I am not able to get the uid, and getUid() obviously wont work either.
So how can I get the uid of the file reference (FAL)
/**
* A file reference object (File Abstraction Layer)
*
* #api experimental! This class is experimental and subject to change!
*/
class FileReference extends
\TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder
{
/**
* Uid of the referenced sys_file. Needed for extbase to serialize the
* reference correctly.
*
* #var int
*/
protected $uidLocal;
/**
* #param \TYPO3\CMS\Core\Resource\ResourceInterface $originalResource
*/
public function setOriginalResource(\TYPO3\CMS\Core\Resource\ResourceInterface $originalResource)
{
$this->originalResource = $originalResource;
$this->uidLocal = (int)$originalResource->getOriginalFile()->getUid();
}
/**
* #return \TYPO3\CMS\Core\Resource\FileReference
*/
public function getOriginalResource()
{
if ($this->originalResource === null) {
$this->originalResource = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileReferenceObject($this->getUid());
}
return $this->originalResource;
}
}
Given you have an instance of TYPO3\CMS\Extbase\Domain\Model\FileReference then you can use getOriginalResource() to get the wrapped TYPO3\CMS\Core\Resource\FileReference. If you need the referenced file, you can then use getOriginalFile(). Thus as a chained call:
$file = $fileReference->getOriginalResource()->getOriginalFile();
Notice that you don't have to use the ResourceFactory yourself in all of this, this is taken care of internally.
Work form me.
You can find or get file refernce uid using custom query.
In Controller :
$uid = $yourObject->getUid();
$fileReference = $this->yourRepository->getFileReferenceObject($uid);
In Repository
public function getFileRefernceHeaderLogo($uid){
$query = $this->createQuery();
$queryString = "SELECT *
FROM sys_file_reference
WHERE deleted = 0
AND hidden = 0
AND tablenames='your_table_name'
AND fieldname='your_field_name'
AND uid_foreign =".$uid;
$query->statement($queryString);
return $res = $query->execute(true);
}
In Controller
$fileRefUid = $fileReference[0]['uid'];
Here you can get uid of file reference table.It is long process.
You can also get sys_file table uid for getFileObject.like,
$sys_file_uid = $fileReference[0]['uid_local'];

Combining TypoScript and Fluid: Iterations?

I'm combining a TypoScript CONTENT Object with a fluid template.
In the page template:
<f:cObject typoscriptObjectPath="lib.myItem" />
In TS:
lib.myItem = CONTENT
lib.myItem {
table = tt_content
select.where = colPos = 0
select.languageField = sys_language_uid
renderObj = FLUIDTEMPLATE
renderObj {
file = {$customContentTemplatePath}/Myfile.html
layoutRootPath = {$customContentLayoutPath}
partialRootPath = {$customContentPartialPath}
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
10.references.fieldName = image
}
}
}
In Myfile.html:
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
<div class="small-12 medium-6 large-4 columns">
<f:for each="{files}" as="file">
<v:media.image src="{file}" srcset="1200,900,600" srcsetDefault="600" alt="{file.alternative}" treatIdAsReference="1"/>
</f:for>
<div class="fp-ql-txt">
{data.header} >
</div>
</div>
But now I realized that because the template is applied by the renderObj for each content element, I don't have access to fluid's for-each information about iteration. So, I can't do this:
<f:for each="{data}" as="item" iteration="itemIterator">
{itemIterator.cycle}
</f:for>
to find out in which of the rendered items we are ... because each element is rendered individually by renderObj.
How can I get the iteration information about the renderObj's products? Only in TS with the old and terrifying counters as in http://typo3-beispiel.net/index.php?id=9 ?
You could make your own IteratorDataProcessor:
<?php
namespace Vendor\MyExt\DataProcessing;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;
use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException;
/**
* This data processor will keep track of how often he was called and whether it is an
* even or odd number.
*/
class IteratorProcessor implements DataProcessorInterface, SingletonInterface
{
/**
* #var int
*/
protected $count = 0;
/**
* Process data for multiple CEs and keep track of index
*
* #param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element
* #param array $contentObjectConfiguration The configuration of Content Object
* #param array $processorConfiguration The configuration of this processor
* #param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
* #return array the processed data as key/value store
* #throws ContentRenderingException
*/
public function process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData)
{
$iterator = [];
$iterator['index'] = $this->count;
$iterator['isFirst'] = $this->count === 0;
$this->count++;
$iterator['cycle'] = $this->count;
$iterator['isEven'] = $this->count % 2 === 0;
$iterator['isOdd'] = !$iterator['isEven'];
$processedData['iterator'] = $iterator;
return $processedData;
}
}
In Typoscript you pass your data through that processor:
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
10 {
references.fieldName = image
}
20 = Vendor\MyExt\DataProcessing\IteratorProcessor
}
In fluid you can access the stuff you set in your DataProcessor with e.g. {iterator.isFirst}.
You should check out the DatabaseQueryProcessor shipped with the TYPO3 Core.
https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/Fluidtemplate/Index.html#dataprocessing
Please note that data processing only work inside the FLUIDTEMPLATE cObject.
You also find a working example inside the documentation.

How to select a random image from files in a directory using typoscript?

I'm using Typo3 4.5.3 and I have image files in a directory from which I want to randomly select one to display on the current page, but I can't seem to get the typoscript right to make listnum = rand work. Here's my extension template:
# Pick a random image to display
temp.banner = IMAGE
temp.banner {
file {
height = 165
width = 954
import {
filelist = {$templatePathPrefix}images/banners | jpg,jpeg,png,gif | name | | 1
listNum = rand
}
}
params = class="bannerPic"
}
If I change the listnum setting to 0, 1, etc. it inserts the corresponding img HTML into the page. Setting it to 'last' also works, but rand always inserts the first image no matter how many times I refresh. Since I can select specific images (0, 1, ...) I know the general setup works, just not the random selection.
I've seen TS for various other uses of rand which wrap the outer object in a COA_INT object, but that didn't work for me either. Did I miss something about where to place the listNum = rand? I'm pretty new at Typo3 so lots of it is still pretty opaque to me at this point (or does it show?). Thanks for any insight you can provide.
mak_stdwrapextended extension adds the possibility to use rand with listNum.
Works well on 4.5.
I would not recommend you to do a random selection via TypoScript. Since you want a random image everytime you load the page, your random element must be a USER_INT or COA_INT element and is therefore not cacheable.
A simple solution for this is to do it via JavaScript. You define a default image if JavaScript is not available on the client, and a JavaScript that randomly select an image. With this solution, you get a random image everytime, and your content is fully cacheable.
The following TypoScript code can give you some inspiration for this. It basically reads out Image-Elements from the border collumn and generates JavaScript to output them randomly. Also, the images are linkable.
lib.teaser = COA
lib.teaser.10 = CONTENT
lib.teaser.10 < styles.content.getBorder
lib.teaser.10 {
slide = -1
table=tt_content
select{
begin = 0
max = 1
#language
languageField=sys_language_uid
#from wich column
where=colPos=3
}
wrap=<div class="teaserimage">|</div>
renderObj=COA
#image with gallery function
renderObj.10 = COA
renderObj.10 {
stdWrap.required=1
# get image
10 = IMAGE
10 {
#if not empty
required=1
file.import=uploads/pics/
file.import.field=image
#file.width=266
#file.height=180
file.import.listNum = 0
stdWrap.insertData=1
params = id="imgbig_{TSFE:currentRecord}"
imageLinkWrap < tt_content.image.20.1.imageLinkWrap
imageLinkWrap.typolink.ATagParams = id="link_imgbig_{TSFE:currentRecord}"
imageLinkWrap.typolink.ATagParams.stdWrap.insertData=1
}
# standard image configuration from tt_content
10.altText < tt_content.image.20.1.altText
10.titleText < tt_content.image.20.1.titleText
10.longdescURL < tt_content.image.20.1.longdescURL
# random function for gallery images
30 = COA
30 {
stdWrap.required=1
stdWrap.dataWrap(
<script type="text/javascript">
/* <![CDATA[ */
var imgArray = new Array(|);
var randnum = Math.round(Math.random()*(imgArray.length-1));
document.getElementById('imgbig_{TSFE:currentRecord}').src ='uploads/pics/' + imgArray[randnum];
/* ]]> */
</script>
)
# first gallery image
10 = TEXT
10.field = image
10.listNum.splitChar=,
10.listNum=0
10.if.isTrue.field=image
10.if.isTrue.listNum=1
10.if.isTrue.listNum.splitChar=,
10.dataWrap = "|"
# other gallery images
20 = TEXT
20.field = image
20.split {
token = ,
cObjNum = 1
1 = COA
1.if.isPositive.data = TSFE:register|SPLIT_COUNT
1 {
10 = TEXT
10.data = current:1
10.dataWrap = ,"|"
}
}
}
# random function for gallery links
40 = COA
40 {
stdWrap.required=1
stdWrap.dataWrap(
<script type="text/javascript">
/* <![CDATA[ */
//var imgLinkArray = new Array(randnum);
var imgLinkArray = new Array(|);
if(document.getElementById('link_imgbig_{TSFE:currentRecord}')) document.getElementById('link_imgbig_{TSFE:currentRecord}').href = imgLinkArray[randnum];
/* ]]> */
</script>
)
# first gallery link
10 = TEXT
10.field = image_link
10.listNum.splitChar=,
10.listNum=0
10.dataWrap = "|"
10.typolink.parameter.field = image_link
10.typolink.returnLast = url
# other gallery links
20 = TEXT
20.field = image_link
20.split {
token = ,
cObjNum = 1
1 = COA
1.if.isPositive.data = TSFE:register|SPLIT_COUNT
1 {
10 = TEXT
10.data = current:1
10.dataWrap = ,"|"
10.typolink.parameter.data = current:1
10.typolink.returnLast = url
}
}
}
}
}
only typo3 V4.6 and above has listNum = rand in the core, see this http://forge.typo3.org/issues/16180
for typo3 V4.5 you have to extend tslib/the class.tslib_content.php
add this to localconf.php:
$TYPO3_CONF_VARS['FE']['XCLASS']['tslib/class.tslib_content.php'] = PATH_site.'fileadmin/template/class.ux_tslib_content.php';
and add this code to class.ux_tslib_content.php:
<?php
/***************************************************************
* Copyright notice
*
* (c) 1999-2008 Kasper Skaarhoj (kasperYYYY#typo3.com)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
* A copy is found in the textfile GPL.txt and important notices to the license
* from the author is found in LICENSE.txt distributed with these scripts.
*
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
* Contains classes for Content Rendering based on TypoScript Template configuration
*
* $Id: class.tslib_content.php 4254 2008-09-27 13:35:44Z dmitry $
* Revised for TYPO3 3.6 June/2003 by Kasper Skaarhoj
* XHTML compliant
*
* class tslib_cObj : All main TypoScript features, rendering of content objects (cObjects). This class is the backbone of TypoScript Template rendering.
*
* #author Kasper Skaarhoj <kasperYYYY#typo3.com>
*/
/**
* This class contains all main TypoScript features.
* This includes the rendering of TypoScript content objects (cObjects).
* Is the backbone of TypoScript Template rendering.
*
* There are lots of functions you can use from your include-scripts.
* The class "tslib_cObj" is normally instantiated and referred to as "cObj".
* When you call your own PHP-code typically through a USER or USER_INT cObject then it is this class that instantiates the object and calls the main method. Before it does so it will set (if you are using classes) a reference to itself in the internal variable "cObj" of the object. Thus you can access all functions and data from this class by $this->cObj->... from within you classes written to be USER or USER_INT content objects.
*
* #author Kasper Skaarhoj <kasperYYYY#typo3.com>
* #package TYPO3
* #subpackage tslib
* #link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&cHash=4ad9d7acb4
*/
class ux_tslib_cObj extends tslib_cObj{
/**
* Exploding a string by the $char value (if integer its an ASCII value) and returning index $listNum
*
* #param string String to explode
* #param string Index-number. You can place the word "last" in it and it will be substituted with the pointer to the last value. You can use math operators like "+-/*" (passed to calc())
* #param string Either a string used to explode the content string or an integer value which will then be changed into a character, eg. "10" for a linebreak char.
* #return string
*/
function listNum($content,$listNum,$char) {
$char = $char ? $char : ',';
if (t3lib_div::testInt($char)) {
$char = chr($char);
}
$temp = explode($char,$content);
$last = ''.(count($temp)-1);
if($listNum === 'rand'){ $listNum = rand(0,count($temp)-1);} //taywa added: rand feature!
$index=$this->calc(str_ireplace('last',$last,$listNum));
return $temp[$index];
}
}
?>