Add header and footer Data - typo3

In My Controller extbase extension. 6.2 I'm using
$GLOBALS['TSFE']->additionalFooterData[$this->extKey] .= '<script src="//cdn.datatables.net/1.10.1/js/jquery.dataTables.min.js"></script>';
Is there any better method for replacing this.
I know the API like
//==== Include Js File Formatting ========
$GLOBALS['TSFE']->getPageRenderer()->addJsFooterFile($jsFile, 'text/javascript', TRUE, FALSE, '', TRUE);
//==== Include css File Formatting =======
$GLOBALS['TSFE']->getPageRenderer()->addCssFile ( $cssFile, $rel = 'stylesheet', $media = 'all', $title = '', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE, $splitChar = '|' );
But in terms of adding a custom data they cant be used, any thing else. Any opinion?.

There are three ways I'd consider:
Build the styles and scripts separately using grunt or some other task runner, and then include the few resulting files globally. This is nice for complete websites, makes collaboration quite easy. Someone provides LESS styles, and you just compile and include them.
Use this ViewHelper from EXT:vhs.
Instead of using $GLOBALS['TSFE'], let extbase inject the page renderer into your code and then do what you are doing now.
/**
* #var \TYPO3\CMS\Core\Page\PageRenderer
* #inject
*/
protected $pageRenderer;
(clear cache in the install tool after inserting this)

Related

Typo3 : add file to FAL when it is not presente in sys_file

I have this situation
I have a table in my db containing some file names in a field1 (eg field1: "my file.ext")
NOTE: the filename does not necessarily pass a Typo3 "sanitizeFilename" check -> it may contain spaces " " or other characters that would be removed by the sanitizeFilename () method
I have the file mentioned above, stored on the server that host typo3
In the sys_file table, the file is not present
the "update storage index" scheduler cannot process all the files, and if i launch it, it "destroy" the file name (my file.ext -> my_file.ext), so the name stored in the field of my table doensn't have much sense anymore.
I would need to absorb the above mentioned files in the FAL, in order to use them in an ext typo3.
I had thought of such a solution
<?php
// read from "field1" of my table
// $filename = the name extracted from my table (e.g. : "my file.ext")
// %path = the path of the file : e.g. "/fileadmin/user_upload")
if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/" . $defaultStorage->getConfiguration()['basePath'] . $path . $filename)) {
// check the folder
if ($defaultStorage->hasFolder($path)) {
$folder = $defaultStorage->getFolder($path);
} else {
throw new \ Exception ($path . "path not found in AbstractImportCommand in method extractFile");
}
// CHECK IF FILE IS IN FAL
$file = $folder->getStorage()->getFileInFolder($filename, $folder);
if ($file) {
// the file already exists in the FAL
} else {
// create new sys_file
$file = $defaultStorage->addFile(
$_SERVER['DOCUMENT_ROOT'] . "/" . $defaultStorage->getConfiguration()['basePath'] . $path . $filename,
$folder,
DuplicationBehavior::REPLACE
);
}
}
Any suggestion?
Put your code into a command.
(optional) create a sys_file_metadata record for your file if you have information that needs to be stored there
create a sys_file_reference to your content record (before that you should adjust TCA accordingly)
For creating the sys_file_reference there is no api. A function doing so could look like this:
/**
* #param $fileUid
* #param $recordUid
* #param $table
*/
private function createSysFileReference($record, $fileUid, $tableName, $fieldName){
$data['sys_file_reference']['NEW_' . uniqid()] = [
'table_local' => 'sys_file',
'uid_local' => $fileUid,
'tablenames' => $tableName,
'uid_foreign' => $record['uid'],
'fieldname' => $fieldName,
'pid' => $record['pid']
];
$dataHandler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
$dataHandler->start($data, []);
$dataHandler->process_datamap();
}
What you consider as "destroying the filename" is indeed preserving file functionality, so sanitizing the filenames is required.
As example consider a file with white space like "My Pdf.pdf". It will be shown eventually like "My%20Pdf.pdf" in the URL and also saved like this. If you link to it, at least the link text won't show the "%20" and the expectation that links and the name of the file are always synchronized (no matter how it's stored) isn't reliable as it probably depends on several parameters like operating system or browser too. The same problem might occur for many different signs too.
Consider that the problems occur not only when a user is downloading a file but also when a file is uploaded, where the wrong url-encoded name is saved in the database, this name might be saved differently in the filesystem or not be found even if the saved value is the same as in the filesystem, due to the url-encoded signs. Your file references are broken on the server then and according links might not work and images not displayed.
So circumventing FAL beside tables is a bad decision and while it's likely possible to write an own sanitizer, I would refrain from dropping it completely.

How to replace src with data-src in TYPO3's YouTube iframe tag?

In order to use the "Klaro! Consent Manager" I need to modify the iframe-tag a little bit, which is automatically generated by TYPO3 when you embed a YouTube video with a textmedia element.
It is generated in /typo3/sysext/core/Classes/Resource/Rendering/YouTubeRenderer.php
public function render(FileInterface $file, $width, $height, array $options = [], $usedPathsRelativeToCurrentScript = false)
{
$options = $this->collectOptions($options, $file);
$src = $this->createYouTubeUrl($options, $file);
$attributes = $this->collectIframeAttributes($width, $height, $options);
return sprintf(
'<iframe src="%s"%s></iframe>',
htmlspecialchars($src, ENT_QUOTES | ENT_HTML5),
empty($attributes) ? '' : ' ' . $this->implodeAttributes($attributes)
);
}
I already have a user_site extension to configure the system and edit the templates, but without any php classes. It looks like I can't just overwrite a fluid template here. I'm an integrator, not an extension developer, and i wonder how i can overwrite or extend this function accordingly, without changing or duplicating too much of the core functions.
How can I replace <iframe src= with <iframe data-name="youtube" data-src=?
Thanks to the comment from nstungcom I have found good samples in the extension media2click and was able to modify the iFrame tag with fragments of this. Since I am not an extension developer, this solution should be used with caution until it is confirmed by a developer. Suggestions for improvement are very appreciated.
I made the following changes / additions to my sitepackage ("user_site" extension):
/ext/user_site/Classes/Resource/Rendering/YouTubeRenderer.php
<?php
namespace MyVendorName\UserSite\Resource\Rendering;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
class YouTubeRenderer extends \TYPO3\CMS\Core\Resource\Rendering\YouTubeRenderer
{
public function getPriority()
{
return 25;
}
public function render(FileInterface $file, $width, $height, array $options = [], $usedPathsRelativeToCurrentScript = false)
{
$options = $this->collectOptions($options, $file);
$iframe = str_replace(' src="', ' src="" data-name="youtube" data-src="', parent::render($file, $width, $height, $options, $usedPathsRelativeToCurrentScript));
return $iframe;
}
}
I'm uncertain if all of those use statements and the getPriority function are really necessary.
/ext/user_site/ext_localconf.php
<?php
defined('TYPO3_MODE') or die();
call_user_func(function () {
$rendererRegistry = \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::getInstance();
$rendererRegistry->registerRendererClass(\MyVendorName\UserSite\Resource\Rendering\YouTubeRenderer::class);
});
I do not know if this is a so-called XCLASS. The syntax looks different from what I found as an example in the Api.
/ext/user_site/ext_emconf.php
<?php
$EM_CONF[$_EXTKEY] = [
'title' => 'Project specific configuration and templates',
// [...]
'autoload' => [
'psr-4' => [
'MyVendorName\\UserSite\\' => 'Classes',
],
],
];
Apparently it needed this autoload, whatever that's for.

how to generate Frontend URI in Scheduler Command (TYPO3 9)

What is the best way to generate frontend URIs in a scheduler command in TYPO3 v9.
I have seen attempts by initializing the TSFE manually, but for me this seems fishy.
Are there any other ways?
The proper way to create links in any context (FE/BE/CLI) is by using the PageRouter. This router is always attached to a site, so you will need to retrieve the correct site first, e.g. by using the SiteFinder. After that you can use PageRouter::generateUri().
Complete example:
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageUid);
$arguments = [
'foo' => 1,
];
// E.g.: "https://example.org/slug-of-page/?foo=1"
$uri = (string)$site->getRouter()->generateUri((string)$pageUid, $arguments);
Notice that this API knows nothing about Extbase and passes through $arguments to the URI so if you need to mimic the behavior of the Extbase UriBuilder you'll need to do that yourself:
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Service\ExtensionService;
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$extensionService = $objectManager->get(ExtensionService::class);
// E.g. "tx_acme_test"
$argumentsPrefix = $extensionService->getPluginNamespace($extensionName, $pluginName);
$arguments = [
$argumentsPrefix => [
'action' => $actionName, // E.g. "bar"
'controller' => $controllerName, // E.g. "Foo"
'foo' => 42,
],
];
// E.g.: "https://example.org/slug-of-page/?tx_acme_test[action]=bar&tx_acme_test[controller]=Foo&tx_acme_test[foo]=42"
// Or with a route enhancer: "https://example.org/slug-of-page/detail/slug-of-foo"
$uri = (string)$site->getRouter()->generateUri((string)$pageUid, $arguments);
Depending on your needs, the native way described by #mathias-brodala might not be sufficient. In those cases you will need a proper TSFE otherwise you do not have all the TypoScript settings that might influence link generation.
For these cases you basically need to create an instance of the TypoScriptFrontendController yourself, call setup methods and inject real or mocked dependencies like FrontendUserAuthentication depending on your usecase.
A working solution for TYPO3v9, for instance, can be found in the
rx_scheduled_social extension.

TYPO3: How to render translated content in extension

I am developing a TYPO3 6.0 plugin that shows the subpages of the current page as tabs. For example, on the following pages my plugin is inserted on TabRoot:
If TabRoot is requested, the plugin's ActionController looks up the database for the subpage titles and contents and passes all gathered data to a Fluid template. The page is then rendered like the following:
With JS in place I always hide/show content below based on the selection. My problem is that I want to show the translated content of the subpages based on the current language selection. How am I able to do this? I've tried it with several methods, but neither of them was flawless. These are the methods I've tried:
Using RECORDS This method is not affected by the selected language, it always returns the content in the default language:
//Get the ids of the parts of the page
$select_fields = "uid";
$from_table = "tt_content";
$where_clause = 'pid = ' . $pageId;
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
$select_fields,
$from_table,
$where_clause,
$groupBy='',
$orderBy='sorting',
$limit=''
);
$ids = '';
$firstIteration = true;
while ( $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc( $res ) ) {
if (!$firstIteration) $ids .= ",";
$ids .= $row ['uid'];
$firstIteration = false;
}
$GLOBALS['TYPO3_DB']->sql_free_result( $res );
//Render the parts of the page
$conf ['tables'] = 'tt_content';
$conf ['source'] = $ids;
$conf ['dontCheckPid'] = 1;
$content = $this->cObj->cObjGetSingle ( 'RECORDS', $conf );
Using CONTENTS According to TYPO3: How to render localized tt_content in own extension, this is the way to do it, however for me this also returns the content rendered with the default language. It is not affected by a language change.
$conf = array(
'table' => 'tt_content',
'select.' => array(
'pidInList' => $pageId,
'orderBy' => 'sorting',
'languageField' => 'sys_language_uid'
)
);
$content = $this->cObj->cObjGetSingle ( 'CONTENT', $conf );
Using VHS: Fluid ViewHelpers I installed the vhs extension and tried to render the content with <v:content.render />. The result is the same as with CONTENTS; it only works with the default language.
{namespace v=Tx_Vhs_ViewHelpers}
...
<v:content.render column="0" order="'sorting'" sortDirection="'ASC'"
pageUid="{pageId}" render="1" hideUntranslated="1" />
Using my own SQL query I've tried to get the bodytext fields of the page and then render those with \TYPO3\CMS\Frontend\Plugin\AbstractPlugin::pi_RTEcssText(). This method returns the content based on the current language, however the problem is that bodytext's do not contain the complete content (images, other plugins, etc).
$select_fields = "bodytext";
$from_table = "tt_content";
$where_clause = 'pid = ' . $pageId
. ' AND sys_language_uid = ' . $GLOBALS ['TSFE']->sys_language_uid;
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
$select_fields,
$from_table,
$where_clause,
$groupBy='',
$orderBy='sorting',
$limit=''
);
$content = '';
while ( $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc( $res ) ) {
$content .=
\TYPO3\CMS\Frontend\Plugin\AbstractPlugin::pi_RTEcssText( $row ['bodytext'] );
}
$GLOBALS['TYPO3_DB']->sql_free_result( $res );
What am I missing? Why isn't the content rendered with the current language in the case of the CONTENTS method?
Easiest way is to use the cObject viewhelper to render right from TypoScript.
And inside your TypoScript template provide the configuration:
lib.myContent = CONTENT
lib.myContent {
...
}
BTW, you are bypassing the TYPO3 CMS API. Please do not do so. Always use the API methods to query for data.
e.g. \TYPO3\CMS\core\Database\DatabaseConnection is always available at GLOBALS['TYPO3_DB']->. Do not use the the mysql function.
On top of that, I believe that you can archive whatever you are trying to do with pure TypoScript, without the need to program anything. Feel free to ask a new questions to get help on this.
In TYPO3 4.x you could use the following methods to load the translated record:
t3lib_pageSelect->getRecordOverlay
t3lib_pageSelect->getPageOverlay
They are also available at $GLOBALS['TSFE']->sys_page->getRecordOverlay().

ZEND tralslations for addMultiOption text in Form for poEdit

I dont have an idea why translations are not working in with Zend_Form.
I would like to be able translate options for selects.
For now i have something like this:
my form class:
(...)
$this->translate = Zend_Registry::get('translate');
Zend_Form::setDefaultTranslator( Zend_Registry::get('translate') );
(...)
$select = new Zend_Form_Element_Select('select');
// $select->addMultiOption('0', $this->translate('Aktywny'));
$select->addMultiOption('0', $this->translate->_('Aktywny'));
$select->addMultiOption('1', 'Nieaktywny');
in my bootstrap file i have something like this:
protected function _initTranslate()
{
Zend_Loader::loadClass('Zend_Translate');
Zend_Loader::loadClass('Zend_Registry');
$translate = new Zend_Translate('gettext', APPLICATION_PATH.'/languages',
'browser',
array('scan' => Zend_Translate::LOCALE_FILENAME));
//changing language and setting it to session if changed
$session = new Zend_Session_Namespace('jezyk');
if(isset($session->language)) {
$translate->setLocale($session->language);
} else
$translate->setLocale('pl');
$registry = Zend_Registry::getInstance();
$registry->set('Zend_Translate', $translate);
}
and it works fine for controllers, phtml files and plugins where i call it by
$this->translate('string to translate');
and in plugins
$this->view->translate('string to translate');
but those methods won't work in form. It throws exception:
Warning: Exception caught by form: No entry is registered for key 'translate' Stack Trace: #0
to make it working as i wrote in comment just have to change line:
$this->translate = Zend_Registry::get('translate');
for
$this->translate = Zend_Registry::get('Zend_Translate');
cause i didn't saw that i'm getting wrong translate from registry. It should be Zend_Translate like in Bootstrap file, not translate as i did.
And this is solution for my problems with translate and now i can make translations in form files :)