"Undeclared arguments passed to ViewHelper" Exception - typo3

After updating TYPO3, I get a TYPO3Fluid\Fluid\Core\ViewHelper\Exception "Undeclared arguments passed to ViewHelper ... Valid arguments are."

Tip: Use rector to make these (and other) conversions! Functions for TYPO3 are available, see
https://usetypo3.com/using-rector-with-typo3.html
This may be due to an extension using functionality that has been dropped. Using only the TYPO3 core, you should not see this error.
In your extension: If you still use the render() method in your ViewHelper class with arguments, you may want to replace this:
before:
public function render(Mail $mail, $type = 'web', $function = 'createAction')
after:
public function initializeArguments()
{
parent::initializeArguments();
$this->registerArgument('mail', Mail::class, 'Mail', true);
$this->registerArgument('type', 'string', 'type: web | mail', false, 'web');
$this->registerArgument('function', 'string', 'function: createAction | senderMail | receiverMail', false, 'createAction');
}
public function render()
{
$mail = $this->arguments['mail'];
$type = $this->arguments['type'] ?? 'web';
// ...
}
Additionally,
if there is no need to use render() (e.g. unless you need to access $this variables), you may want to switch to renderStatic() for performance reasons (see also this other Stack Overflow answer "What is the difference between render() and renderStatic() ..." for clarification)
inherit from classes in TYPO3Fluid\Fluid\Core\ViewHelper instead of TYPO3\CMS\Fluid\Core\ViewHelper:
// use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
Documentation:
Developing a Custom ViewHelper
Changelogs:
Breaking: #82414 - CMS ViewHelper base classes removed (>= TYPO3 9.0)
Deprecation: #81213 - Render method arguments on ViewHelpers deprecated (>= TYPO3 9.0)
Breaking: #87193 - Deprecated functionality removed (>= TYPO3 10.0)

You are using other extension that makes this error, for example: https://github.com/lochmueller/calendarize/issues/280
If you have a parameters in a ViewHelper, you send them as arguments from Fluid Template. In TYPO3 this error throws when in render() function not have comments about parameters. You have to include them.
Example:
<?php
namespace VENDOR\ExtensionName\ViewHelpers;
class ExampleViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
*
* #param int $foo
* #return boolean
*/
public function render($foo) {
//function render lines
return $bar_boolean;
}
}

Related

TYPO3 - Fluid Translate in PHP ViewHelper within extension

Using PHP 8.7.17
I have the following viewhelper to give an example of what I require
<?php namespace SRS\SrsPccLog\ViewHelpers;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
class ShowDateAsStringViewHelper extends AbstractViewHelper
{
public function initializeArguments()
{
$this->registerArgument('month', 'integer', 'month value', true);
}
public function render()
{
$month = $this->arguments['month'];
return $this->monthAsString($month, $year);
}
public function monthAsString ($month) {
switch ($month) {
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
default:
return "";
}
}
I have the function but what I simply want to do is display the month in the native language, ie replace return "January'
with <f:translate key="tx_srspcclog_domain_model_myext.january" />
so that I can be less language specific and get the language from the language files like i do for a fluid view. Any ideas of how to do this when you not in a fluid view but a PHP view helper
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($key, $extensionName)
Look inside the TranslateViewHelper and see how they did it (most likely the translate(...) method), and use the code to render your own labels from your XLFF files
What you are actually looking for is "%B".
As the documentation clearly states, the FormatDate ViewHelper understands format strings in strftime() as well as date() format. strftime already has localization built in. You don't need to translate anything yourself.
https://docs.typo3.org/typo3cms/ExtbaseGuide/Fluid/ViewHelper/Format/Date.html#localized-time-using-strftime-syntax
http://php.net/manual/de/function.strftime.php

Wordpress Plugins / Custom Class / get_option() / shortcode

I'm having an issue displaying information returned from a custom class defined within a plugin's files, when using a shortcode. I'll write up some mock files that showcase my issue.
/wp-content/plugins/my-plugin/classes/my_class.php
<?php
class People {
public $api_url = "https://www.external-service.com/api";
private $api_key;
function __construct($key = null) {
if $(key) {
$this->api_key = $key;
}
function get_response() {
$path = $this->api_url . "?my_api_token=" . $this->api_key;
}
}
?>
/wp-content/plugins/my-plugin/my-plugin.php
<?php
/**
* all of the wordpress plugin comments
* ...
*/
require "myplg_options.php";
require "myplg_shortcodes.php";
The options page and menu is generated from myplg_options; it is functioning correctly (including using get_option to retrieve the saved option (in this case, the api key).
/wp-content/plugins/my-plugin/myplg_shortcodes.php
<?php
require "classes/my_class.php";
$options = get_option('myplg_settings');
$myplg = new People($options['myplg_api_key']);
$response = $myplg->get_response();
function myplg_list_result(){
echo "the shortcode is working!";
var_dump($options, $myplg, $respnose);
}
add_shortcode('myplg_list', 'myplg_list_result');
?>
Testing externally from wordpress, the class works and everything is fine and dandy. The plugin's option page sets and retains the single option perfectly; the shortcode actually registers and is usable from within a WordPress page/portfolio/etc.
The issue I'm having is that using var_dump, all three of those variables are dumped as NULL.
After doing some homework, I was able to determine that moving the three variable declarations inside the shortcode makes it work. It would seem to me, however, that doing that is not the best workflow, as I'd need to re-grab the option, instantiate a new class, and call the class' function for every shortcode.
Is there a way around this?
As mentioned in the comment it's because variables are function scoped. You may be better off using a Closure.
<?php
require "classes/my_class.php";
$options = get_option('myplg_settings');
$myplg = new People($options['myplg_api_key']);
$response = $myplg->get_response();
add_shortcode('myplg_list', function() use ($options, $response, $myplg) {
echo "the shortcode is working!";
var_dump($options, $myplg, $respnose);
});

Is there a Fluid viewhelper to truncate an URL? If not, how do I make one?

In TYPO3's Fluid or in Fedext/vhs, is there a viewhelper that can convert
http://www.stackoverflow.com/questions/ask
into
www.stackoverflow.com
?
PS: that's the goal:
<f:format.raw><f:link.external uri="{item.link}">{item.just-display-the-domain}</f:link.external></f:format.raw>
EDIT (adapting the question to the answer I got): If I have to build a custom view helper, how do I proceed?
I really doubt if there would be any sensible reason for adding this kind of VH into the core, de facto, writing custom VH is like a piece of cake (when you finally realize it is) so simple formatters can be created by devs in their custom tool exts just in minutes.
Ie. in TYPO3 4.x assuming that you have a custom extension with key urs all you need to do is create one proper class, containing render($params) method and extending Tx_Fluid_Core_ViewHelper_AbstractViewHelper class:
/typo3conf/ext/urs/Classes/ViewHelpers/GetDomainViewHelper.php:
<?php
class Tx_Urs_ViewHelpers_GetDomainViewHelper extends Tx_Fluid_Core_ViewHelper_AbstractViewHelper {
/**
* #param $link string Each `allowed` param need to have its line in PHPDoc
* #return string
*/
public function render($link) {
$link = str_replace('http://', '', $link);
$link = str_replace('https://', '', $link);
$segments = explode('/', $link);
return trim($segments[0]);
}
}
?>
Next in your templae declare its namespace and... that's all, you can use it:
{namespace urs=Tx_Urs_ViewHelpers}
<urs:getDomain link="http://stackoverflow.com/questions/20499453" />
Take special attention about letter case in things like Tx_Urs_ViewHelpers... etc.
More details in http://docs.typo3.org/typo3cms/ExtbaseFluidBook/8-Fluid/8-developing-a-custom-viewhelper.html
In TYPO3 ver. 6.x
Things works preaty similar the main change of course is new namespacing
/typo3conf/ext/urs/Classes/ViewHelpers/GetDomainViewHelper.php:
<?php
namespace TYPO3\Urs\ViewHelpers;
class GetDomainViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* #param $link string Each `allowed` param need to have its line in PHPDoc
* #return string
*/
public function render($link) {
$link = str_replace('http://', '', $link);
$link = str_replace('https://', '', $link);
$segments = explode('/', $link);
return trim($segments[0]);
}
}
In templates:
{namespace urs=TYPO3\Urs\ViewHelpers}
<urs:getDomain link="http://stackoverflow.com/questions/20499453" />
Of course in both cases instead of using hardcoded links you will use:
<urs:getDomain link="{item.link}" />
It's a little bit cumbersome and not very efficient, but it should work and would of course prevent the need for a custom ViewHelper class:
With protocol:
{url -> v:iterator.explode(glue: '/') -> v:iterator.slice(length: 3) -> v:iterator.implode(glue: '/')}
Without protocol:
{url -> v:iterator.explode(glue: '/') -> v:iterator.slice(start: 2, length: 1) -> v:iterator.first()}
Where {url} can come from anywhere, as long as it contains a full http:// or other protocol prefix. The line above of course explodes the URL into parts separated by / then slices off the first three segments and re-joins those using /. Or it simply picks offset 2 (which would be the full domain without protocol) and returns that single element. The result should be an url to the domain of the link, with or without protocol, without trailing slash (which you may or may not want to add yourself after cutting the URL).
Cheers,
Claus
All ViewHelper are located at typo3/sysext/fluid/Classess/ViewHelper. There are also examples in the header of each file. All ViewHelper of Fedext can be reviewed on the website.

How to declare unlimited/variadic parameters in DocBlock?

Lets say I have a function (obviously a trivial example):
public function dot(){
return implode('.', func_get_args());
}
Now I know I could modify this to be
public function dot(array $items){
return implode('.', $array);
}
but with some functions that is not an option. So, how would you document the first version of the function with a docBlock so an IDE can interpret that it can receive unlimited parameters?
I have seen some methods that use:
/**
* Joins one or more strings together with a . (dot)
* #param string $string1
* #param string $string2
* #param string $_ [optional]
* #return string
*/
public function dot($string1, $string2, $_ = null) {
return implode('.', func_get_args());
}
Which in an IDE looks like
But that feels like a hack to me, is there no way to do it just with docBlock?
[UPDATED 2015-01-08]
Old way to do this in PHPDoc was:
http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.param.pkg.html
/**
* #param int $param,...
**/
However, this is no longer supported. As of PHP 5.6 Variadic Method Parameters are a part of the PHP language, and the PHPDoc's have been updated to reflect this as of PHPDoc 2.4 if I recall correctly. This is also in the PhpStorm IDE as of EAP 139.659 (should be in 8.0.2 and up). Not sure about implementation of other IDEs.
https://youtrack.jetbrains.com/issue/WI-20157
In any case, proper syntax for DocBlocks going forward for variadic parameters is:
/**
* #param int ...$param
**/
As Variadics are implemented in PHP 5.6 PHPDocumentor should support the following syntax as of version 2.4.
/**
* #param Type ...$value
* Note: PHP 5.6+ syntax equal to func_get_args()
*/
public function abc(Type ...$value) {}
This should be the correct way to describe such a signature. This will likely be included in PSR-5. Once that is accepted IDE's should follow to support this "official" recommendation.
However, in the mean time some IDE's have an improved understanding of what they consider correct. Hit hard on the IDE vendor to support the offical PHP syntax that is supported as of 5.6 or use whatever works in the meantime.
In php the concept of valist or list of "optional arguments" does not exist.
the $_ variable will just contain, here the third string you give.
The only way to allow an array OR a string is to test the first argument with is_array()
public function dot($arg1){
if(is_array($arg1)){
return implode('.',$arg1);
}
else if $arg1 instanceof \Traversable){
return implode('.',iterator_to_array($arg1));
}
else{
return implode('.',func_get_args());
}
}
Now that you handled the behaviour you want, you have to document it. In php, as overloading is not allowed, a convention is to use "mixed" as a type if you want to provide multiple types.
/**
*#param mixed $arg1 an array, iterator that will be joined OR first string of the list
*#return string a string with all strings of the list joined with a point
*#example dot("1","2","3"); returns 1.2.3 dot(array(1,2,3)); returns 1.2.3
*/
Moreover, according to phpdocumentor documentation you can declare sort of valist with
/**
*#param string ... list of strings
*/

Wordpress: Accessing A Plugin's Function From A Theme

I'm trying to add some functionality from a plugin I have made into a Wordpress theme but I am having little joy. The documentation doesn't really help me solve the problem so perhaps someone here can help.
I have a plugin in Wordpress that is activated and working fine. The class for this plugin has a function called generateHtml which I would like to access from a Wordpress Theme. But whatever I try, I cannot seem to access my plugin's code.
Can either give me a summary of what I need to do to get a theme accessing code from a plugin and/or point out there I am going wrong in my code:
Plugin:
<?php
/** Usual comments here **/
if (!class_exists("ImageRotator")) {
class ImageRotator {
private $uploadPath = '';
private $pluginPath = '';
private $options;
function __construct() {
$this->uploadPath = dirname(__file__).'\\uploads\\';
// add_shortcode('imagerotator', array(&$this, 'generateHtml'));
}
// Various functions for plugin
function generateHtml() {
echo '<p>Hello World</p>';
}
}
}
/**
* Create instance of image rotator
*/
$imageRotator = new ImageRotator();
/**
* Create actions & filters for Wordpress
*/
if (isset($imageRotator)) {
// Actions
add_action('admin_menu', array(&$imageRotator, 'createMenu'));
add_action('admin_init', array(&$imageRotator, 'registerSettings'));
add_action('imagerotator_show', array(&$imageRotator, 'generateHtml'));
}
Portion from theme header page:
<?php if (isset($imageRotator)) {
$imageRotator->generateHtml();
} else if (isset($ImageRotator)) {
print_r($ImageRotator);
} else {
echo '<p>Nope!</p>';
}
if (function_exists("imagerotator_show")) {
echo 'Function found';
} else {
echo 'Function NOT found';
}
?>
Currently all I ever see is "Nope" and "Function NOT found". Thanks for any input.
Lee,
For starters, "imagerotator_show" is not a function; it's the name of a type of action. When you use the add_action() function, Wordpress just adds your method to the list of functions/methods to call when a particular action is triggered. Thus your second test will always respond with 'Function NOT found'.
The most likely cause of the first problem is failing to declare the method you want to call as a public method. You're also making the code harder than it needs to be.
The best practice I've seen for declaring methods and registering hooks from a class looks something like this:
if ( ! class_exists( 'Foo' ) ):
class Foo {
function __construct() {
add_action( 'hook_name', array( &$this, 'my_hook_implementation' ) );
}
function my_hook_implementation() {
// does something
}
public function my_special_method() {
// does something else
}
}
if ( class_exists( 'Foo' ) ):
$MyFoo = new Foo();
This allows your class to keep all of its implementation details private. When you need to call my_special_method(), you do it as follows:
$MyFoo->my_special_method();
#andrew since I can't comment I thought I would answer your ancillary question. See:
http://net.tutsplus.com/tutorials/wordpress/create-wordpress-plugins-with-oop-techniques/
Where it is explained that when defining a callback function from an object you have to use the array function. It's basically saying get the function 'my_hook_implementation' from the object $this and use it as the callback parameter to the add action hook. It is because you defined the function within the scope of the object and you have to define the scope in order for PHP to know what function you are talking about. The scope being the object referred to by the variable $this.
You just need to use do_action() function, inside your theme.
If you want the function generateHtml to appears inside your header.php you just need to open the header.php file and paste <?php do_action('imagerotator_show'); ?> where you want and then your function will be called there.