With TYPO3 9.5 I try to manage the URLs from my extension with a custom aspect. The url-generation works but there is a cHash appended. First, I don't want this cHash (it's unnecessary here) and second the cHash breaks the functionality of the link (I get a cHash-comparsion-error).
I read https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/9.5/Feature-86365-RoutingEnhancersAndAspects.html#impact another time about the dynamic parameters and cHash. To remove cHash I should add aspects for all placeholders. I have just one placeholder and an aspect for this, but cHash is present.
raw-url looks like this:
&tx_psoabilling_pi1[action]=showband&tx_psoabilling_pi1[controller]=Band&tx_psoabilling_pi1[band]=564&cHash=jkg24hwek8ufhqwezweklfzh
it's rendered to something like this:
2019-thisisaname?cHash=o28z3hkwejghweuhzlk
Here the part from config.yaml:
PsoabillingPlugin:
type: Extbase
extension: Psoabilling
plugin: Pi1
routes:
- routePath: '/{yearandbandname}'
_controller: 'Band::showband'
_arguments:
yearandbandname: band
defaultController: 'Band::listyear'
aspects:
yearandbandname:
type: BandAndYearMapper
BandAndYearMapper.php
<?php
namespace EnzephaloN\ThemePsoa\Routing\Aspect;
use TYPO3\CMS\Core\Routing\Aspect\PersistedMappableAspectInterface;
use TYPO3\CMS\Core\Site\SiteLanguageAwareTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
class BandAndYearMapper implements PersistedMappableAspectInterface{
use SiteLanguageAwareTrait;
/**
* #param string $value
* #return string|null
*/
public function generate(string $value): ?string{
if($uid=intval($value)){
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_psoabilling_domain_model_band');
$statement = $queryBuilder
->select('b.uid', 'b.name', 'y.year')
->from('tx_psoabilling_domain_model_band','b')
->leftJoin('b', 'tx_psoabilling_domain_model_year', 'y', 'b.year = y.uid')
->where(
$queryBuilder->expr()->eq('b.uid', $queryBuilder->createNamedParameter($uid))
)
->execute();
if($record = $statement->fetch()){
if(is_array($record)){
return $record['year']. "-" .str_replace(" ","-",trim(strtolower($record['name'])));
}
}
}
return null;
}
/**
* #param string $value
* #return string|null
*/
public function resolve(string $value): ?string{
$year = substr($value, 0, 4);
$name = str_replace("-", " ", substr($value, 5));
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_psoabilling_domain_model_band');
$statement = $queryBuilder
->select('b.uid')
->from('tx_psoabilling_domain_model_band','b')
->leftJoin('b', 'tx_psoabilling_domain_model_year', 'y', 'b.year = y.uid')
->where(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('y.year', $queryBuilder->createNamedParameter($year)),
$queryBuilder->expr()->orX(
$queryBuilder->expr()->like('b.name', $queryBuilder->createNamedParameter($name)),
$queryBuilder->expr()->like('b.name', $queryBuilder->createNamedParameter(substr($value, 5))), // if there was a - inside the bandname
$queryBuilder->expr()->like('b.name', $queryBuilder->createNamedParameter(substr($value, 5, strpos($name, " ")-1).'%')) // just find by beginning
)
)
)
->execute();
if($record = $statement->fetch()){
return (string)$record['uid'];
}
return null;
}
}
How can the cHash be removed??
Like Susi wrote, switching to StaticMappableAspectInterface was the solution. The class now starts with:
<?php
namespace EnzephaloN\ThemePsoa\Routing\Aspect;
use TYPO3\CMS\Core\Routing\Aspect\StaticMappableAspectInterface;
use TYPO3\CMS\Core\Site\SiteLanguageAwareTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
class BandAndYearMapper implements StaticMappableAspectInterface{
Related
I have created a view helper in TPYO3 11.
<?php
namespace DN\RisaProjects\Viewhelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
class TestViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
protected $escapeOutput = false;
public function initializeArguments()
{
// registerArgument($name, $type, $description, $required, $defaultValue, $escape)
$this->registerArgument('test', 'string', 'test', true);
}
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
)
{
return $arguments['test'];
}
}
The namespace is registered in ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['rp'] = [
'DN\RisaProjects\ViewHelpers',
];
In the Fluid template I use it like this
<rp:test test="hallo" />
As far as how I have always done it so far. The first call also works. But when the page is loaded from the cache, the viewhelper class is no longer found.
Fluidcache File:
$output0 .= DN\RisaProjects\Viewhelpers\TestViewHelper::renderStatic($arguments36, $renderChildrenClosure37, $renderingContext);
Class "DN\RisaProjects\Viewhelpers\TestViewHelper" not found
What could be the reason for that? I have checked the syntax several times and the autoload files are also correct. The first call also works.
I need to add a custom validator to the datepicker field. By default, this field comes without any validators.
I've already made the validator settings visible in the TCA of tx_powermail_domain_model_field and added my custom validator as usual.
Now I need the attributes data-parsley-customXXX and data-parsley-error-message added to the HTML input field which is usually done via the the viewhelper in ValidationDataAttributeViewHelper.php:
https://github.com/einpraegsam/powermail/blob/develop/Classes/ViewHelpers/Validation/ValidationDataAttributeViewHelper.php#L342
https://github.com/einpraegsam/powermail/blob/develop/Classes/ViewHelpers/Validation/ValidationDataAttributeViewHelper.php#L348
This is the code I need to extend:
https://github.com/einpraegsam/powermail/blob/develop/Classes/ViewHelpers/Validation/DatepickerDataAttributeViewHelper.php#L32
I found a solution for my problem. As suggested in the comment it's possible to extend the Viewhelper:
ext_localconf.php:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\In2code\Powermail\ViewHelpers\Validation\DatepickerDataAttributeViewHelper::class] = [
'className' => \Vendor\MyExt\Powermail\ViewHelpers\Validation\DatepickerDataAttributeViewHelper::class
];
myext/Classes/Powermail/ViewHelpers/Validation/DatepickerDataAttributeViewHelper.php
<?php
declare(strict_types=1);
namespace Vendor\MyExt\Powermail\ViewHelpers\Validation;
use In2code\Powermail\Domain\Model\Field;
use In2code\Powermail\Utility\LocalizationUtility;
class DatepickerDataAttributeViewHelper extends \In2code\Powermail\ViewHelpers\Validation\DatepickerDataAttributeViewHelper
{
/**
* Returns Data Attribute Array Datepicker settings (FE + BE)
*
* #return array for data attributes
*/
public function render(): array
{
/** #var Field $field */
$field = $this->arguments['field'];
$additionalAttributes = $this->arguments['additionalAttributes'];
$value = $this->arguments['value'];
$additionalAttributes['data-datepicker-force'] =
$this->settings['misc']['datepicker']['forceJavaScriptDatePicker'];
$additionalAttributes['data-datepicker-settings'] = $this->getDatepickerSettings($field);
$additionalAttributes['data-datepicker-months'] = $this->getMonthNames();
$additionalAttributes['data-datepicker-days'] = $this->getDayNames();
$additionalAttributes['data-datepicker-format'] = $this->getFormat($field);
if ($value) {
$additionalAttributes['data-date-value'] = $value;
}
if ($field->getValidation() && $this->isClientValidationEnabled()) {
$value = 1;
if ($field->getValidationConfiguration()) {
$value = $field->getValidationConfiguration();
}
$additionalAttributes['data-parsley-custom' . $field->getValidation()] = $value;
$additionalAttributes['data-parsley-error-message'] =
LocalizationUtility::translate('validationerror_validation.' . $field->getValidation());
}
$this->addMandatoryAttributes($additionalAttributes, $field);
return $additionalAttributes;
}
}
I want to add the subheader to the ctype 'textmedia' (TYPO3 9.5 & 10.4).
I followed this stackoverflow answer:
TYPO3 8 show layout selection in backend preview for textmedia
to register my Hook
typo3conf/ext/my-extension/Classes/Hooks/PageLayoutView/TextMediaCustomPreviewRenderer.php
Then I added the subheader
<?php
namespace aaa\bbb\Hooks\PageLayoutView;
use \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface;
use \TYPO3\CMS\Backend\View\PageLayoutView;
/**
* Contains a preview rendering for the page module of CType="textmedia"
*/
class TextMediaCustomPreviewRenderer implements PageLayoutViewDrawItemHookInterface
{
/**
* Preprocesses the preview rendering of a content element of type "textmedia"
*
* #param \TYPO3\CMS\Backend\View\PageLayoutView $parentObject Calling parent object
* #param bool $drawItem Whether to draw the item using the default functionality
* #param string $headerContent Header content
* #param string $subheaderContent Subheader content
* #param string $itemContent Item content
* #param array $row Record row of tt_content
*/
public function preProcess(
PageLayoutView &$parentObject,
&$drawItem,
&$headerContent,
&$subheaderContent,
&$itemContent,
array &$row
) {
if ($row['CType'] === 'textmedia') {
if ($row['bodytext']) {
$itemContent .= $parentObject->linkEditContent($parentObject->renderText($row['bodytext']), $row) . '<br />';
}
if ($row['assets']) {
$itemContent .= $parentObject->linkEditContent($parentObject->getThumbCodeUnlinked($row, 'tt_content', 'assets'), $row) . '<br />';
$fileReferences = BackendUtility::resolveFileReferences('tt_content', 'assets', $row);
if (!empty($fileReferences)) {
$linkedContent = '';
foreach ($fileReferences as $fileReference) {
$description = $fileReference->getDescription();
if ($description !== null && $description !== '') {
$linkedContent .= htmlspecialchars($description) . '<br />';
}
}
$itemContent .= $parentObject->linkEditContent($linkedContent, $row);
unset($linkedContent);
}
}
$drawItem = false;
}
}
}
I get the errror:
Fatal error: Declaration of aaaa\bbb\Hooks\PageLayoutView\TextMediaCustomPreviewRenderer::preProcess(TYPO3\CMS\Backend\View\PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$subheaderContent, &$itemContent, array &$row) must be compatible with TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface::preProcess(TYPO3\CMS\Backend\View\PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row) in /kunden/1111/rp-hosting/2222/333/typo3cms/projekt1/typo3conf/ext/my-sitepackage/Classes/Hooks/PageLayoutView/TextMediaCustomPreviewRenderer.php on line 23
What do I have to do to make it compatible with
TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface::preProcess(TYPO3\CMS\Backend\View\PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row)
You got it a bit wrong. You do not add the subheader in your process() arguments. In general, the arguments must be the same as the class that they extend. You can add the subheader inside the if ($row['CType'] === 'textmedia') {} by adding the value in the itemContent
$itemContent .= $row['subheader'];
Personally i would avoid to do it this way. My preferred choice is to call the StandAlone View and assign a template for preview. Is easier to maintain and program it.
I created (my first) extension with one viewhelper.
Oops, an error occurred!
Could not analyse class:My\Mlv\ViewHelpers\Format\ReplacenewlinesViewHelper maybe not loaded or no autoloader?
In use (with news):
{namespace m=My\Mlv\ViewHelpers}
{newsItem.bodytext -> m:format.replacenewlines()}
Directory tree of extension:
typo3conf/ext/mlv
ext_emconf.php (copied from another ext)
/Classes
/ViewHelpers
/Format
ReplaceNewLinesViewHelper.php
ReplaceNewLinesViewHelper.php:
<?php
namespace My\Mlv\ViewHelpers\Format;
/**
* Replaces newlines in plain text with <br> tags.
*
* #author johndoe33
* #package Mlv
* #subpackage ViewHelpers\Format
*/
class ReplaceNewLinesViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* Replaces newlines in plain text with <br> tags.
*
* #param string $content
* #return string
*/
public function render($content = NULL) {
if (NULL === $content) {
$content = $this->renderChildren();
}
$content = str_replace( "\n", '<br>', $content );
return $content;
}
}
You need to use camel case in the view helper invocation:
{newsItem.bodytext -> m:format.replaceNewLines()}
Furthermore you may need to define an autoload definition in your ext_emconf.php if you're using TYPO3 >=7.6 (reinstall the extension after doing so):
'autoload' => array(
'psr-4' => array('My\\Mlv\\' => 'Classes')
)
For more information see: http://insight.helhum.io/post/130876393595/how-to-configure-class-loading-for-extensions-in
I'm trying to build a query string as following:
Next Page
I want to add an array to query string. For example, array('find_loc'=>'New+York', 'find_name'=>'starbucks')
I expect to get url that looks like http://example.com/1/?find_loc=New+York&find_name=starbucks
What's the best way to do this? I found a similar question that suggested appending the string to the url. Is there a helper for query string?
Simple answer to your question is no.
Here is the class description:
/**
* Helper for making easy links and getting urls that depend on the routes and router
*
* #package Zend_View
* #subpackage Helper
* #copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
* #license http://framework.zend.com/license/new-bsd New BSD License
*/
Helper for making easy links and getting urls that depend on the routes and router
I think the description is clear in it's purpose. Use it for making URLs that depend on the routes and router. So, just append your query strings as recommend in the link you posted in your question.
The following should work for you:
Next Page
The ZF-Router will map the values to the Request object.
In your controller you can access these params with the Response-Object:
$loc = $this->getRequest()->getParam('find_loc');
$name = $this->getRequest()->getParam('find_name);
You can make custom helper:
class My_View_Helper_UrlHttpQuery extends Zend_View_Helper_Abstract
{
public function urlHttpQuery($query)
{
$urlHelper = $this->view->getHelper('url');
$params = func_get_args();
array_shift($params);//removing first argument
$url = call_user_func_array(($urlHelper, 'url'), $params);
if(!is_string($query)) { //allow raw query string
$query = array($query);
$query = http_build_query($query);
}
if(!empty($query) {
$url .= '?' . ltrim('?', $query);
}
return $url;
}
}
After you register this helper with view, you can use it like this Next Page
Working code
/**
* Class Wp_View_Helper_UrlHttpQuery
*/
class Wp_View_Helper_UrlHttpQuery extends Zend_View_Helper_Abstract
{
public function urlHttpQuery($query = array())
{
$urlHelper = $this->view->getHelper('url');
$params = func_get_args();
//removing first argument
array_shift($params);
$url = call_user_func_array(array($urlHelper, 'url'), $params);
if (is_array($query) || is_object($query)) {
$query = http_build_query($query);
}
if (!empty($query)) {
$url .= '?' . ltrim($query, '?');
}
return $url;
}
}
since the upstream code doesn't work