Undeclared arguments passed to ViewHelper - typo3

I upgraded a website from TYPO3 v7 to v9 and now I get the following error:
Undeclared arguments passed to ViewHelper \ViewHelpers\MyViewHelper: value, list. Valid arguments are: [...]
My current ViewHelper looks as follows:
<?php
namespace VP\News\ViewHelpers;
/**
* #package TYPO3
* #subpackage Fluid
*/
class InListViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* #param mixed $value value
* #param mixed $list list
* #return boolean
*/
public function render($value, $list) {
if (!is_array($list)) {
$list = str_replace(' ', '', $list);
$list = explode(',', $list);
}
return in_array($value, $list);
}
}

Some things have changed between v7 and v9 ViewHelpers in TYPO3 Fluid.
➊ You should extend from the abstract class TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper.
➋ You have to register the arguments you pass to the ViewHelper.
➌ Your ViewHelper looks more like a Condition-ViewHelper than an Abstract-ViewHelper.
The first point is self-explanatory. Simply change the name of the base class (the fully qualified class name). For the second point, you can use an additional method initializeArguments(). For example:
public function initializeArguments(): void
{
parent::initializeArguments();
$this->registerArgument('value', 'type', 'description');
...
}
You can find an example here.
However, your ViewHelper seems to check a condition ("is this element in a list?", "then...", "else..."). Therefore, it might be better to implement a Condition-ViewHelper.
This type of ViewHelper extends the class TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper and evaluates a condition using a method verdict() instead of render() or renderStatic().
You can find an example of a simple Condition-ViewHelper here.

Related

Virtual properties in TYPO3 extbase domain models?

I'm trying to use a virtual domain model property in TYPO3 9.5.x that doesn't have a database field representation but I can't get it to work.
My model looks like this
class Project extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
/**
* participants
*
* #var string
*/
protected $participants;
...
/**
* Returns the participants
*
* #return string $participants
*/
public function getParticipants()
{
$this->participants = "foo";
return $this->participants;
}
}
I do see the property when I debug the model but it's always null as if it doesn't even recognise the getter method getParticipants().
Any idea what I might be doing wrong?
Already added a database field to ext_tables.sql and the TCA, but it didn't seem to make a difference.
The property is null because that's the state when the Extbase debugger inspects it. Notice that the Extbase debugger knows nothing about getters and also does not call them.
So if you want to initialize your property you must do this at the declaration time:
protected $participants = 'foo';
You can debug this property by simpy accessing it.
In Fluid, if you use <f:debug>{myModel}</f:debug>, you will see NULL for your property.
But if you directly use <f:debug>{myModel.participants}</f:debug>, you will see 'foo'.

How to get current WordPress category in FishPig in Magento 2?

What is the most straightforward way to get the current category in the view? I notice that there is a getTerm method in the Term class:
public function getEntity()
{
return $this->getTerm();
}
/**
* Returns the current Wordpress category
* This is just a wrapper for getCurrentCategory()
*
* #return \FishPig\WordPress\Model\Term
*/
public function getTerm()
{
if (!$this->hasTerm()) {
$this->setTerm($this->_registry->registry(Term::ENTITY));
}
return $this->_getData('term');
}
However if I try to utilize the method within a template (for example, the default post list wrapper.phtml template which utilizes the Term block in the layout) it throws an error:
<?php echo $this->getTerm() ?>
Recoverable Error: Object of class FishPig\WordPress\Model\Term could
not be converted to string in
I'm probably just missing something simple, any help would be greatly appreciated. Thanks!
$term = \Magento\Framework\App\ObjectManager::getInstance()
->get('Magento\Framework\Registry')
->registry('wordpress_term');

Flexform Hook of tx_news not working in TYPO3 8.x

In my Extension I'm using the backendUtility Hook of the tx_news Extension. It works well in previos versions of TYPO3.
/**
* #param array|string $params
* #param array $reference
* #return void
*/
public function updateFlexforms(&$params, &$reference) {
if ($params['selectedView'] === 'News->calendar') {
$removedFields = $this->removedFieldsInCalendarView;
$this->deleteFromStructure($dataStructure, $removedFields);
}
}
In TYPO3 8.3 and 8.4 I got the following warning:
1: PHP Warning: Declaration of \Foo\BarBackendUtility::updateFlexforms(&$params, &$reference) should be compatible with GeorgRinger\News\Hooks\BackendUtility::updateFlexforms(array &$dataStructure, array $row) in /path/to/BackendUtility.php line 0
As it is a hook and it needs these parameters params and reference, I can not change it to the parameters of the original function. This would also lead to an issue.
What am I missing here?
Just rename your updateFlexform method to a different name.
Problem is because of php7
The first answer and the comment in the same thread (both by Georg Ringer) combined leads to the solution:
/**
* #param array $params
* #param array $reference
* #return void
*/
public function updateFlexformsDatedNews(&$params, &$reference) {
if ($params['selectedView'] === 'News->calendar') {
$removedFields = $this->removedFieldsInCalendarView;
$this->deleteFromStructure($params['dataStructure'], $removedFields);
}
}
This works with PHP5.6 and 7.0
This is PHP Warrnig message, Becaue in TYPO3 8 core updateFlexforms() function pass two parameters with always type array. You need to pass array value in this function.

Doctrine annotation exception when using parse query in Symfony2

I'm trying to make an API Rest in Symfony2 using Parse as cloud database.
If I try to retrieve the Parse users it works fine and returns the expected data.
Local url example: http://www.foo.local/app_dev.php/getUsers/
Here is the code I use in the Users controller (I use annotations in order to set the routes in the controller):
namespace Foo\ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Parse\ParseClient;
use Parse\ParseObject;
use Parse\ParseQuery;
use Parse\ParseUser;
class UsersController extends Controller
{
/**
* #return array
* #View()
* #Route("/getUsers/")
*/
public function getUsersAction(Request $request) {
ParseClient::initialize(<my Parse keys>);
$query = ParseUser::query();
$results = $query->find();
return array('users' => $results);
}
}
However if I try the same with my Products ParseObjects, I get the following error message:
error code="500" message="Internal Server Error" exception
class="Doctrine\Common\Annotations\AnnotationException"
message="[Semantical Error] The annotation "#returns" in method
Parse\ParseFile::getData() was never imported. Did you maybe forget to
add a "use" statement for this annotation?"
Local url example: http://www.foo.local/app_dev.php/getProducts/
The Products controller code:
namespace Foo\ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Parse\ParseClient;
use Parse\ParseObject;
use Parse\ParseQuery;
use Parse\ParseUser;
use Parse\ParseFile;
class ProductsController extends Controller
{
/**
* #return array
* #View()
* #Route("/getProducts/")
*/
public function getProductsAction(Request $request) {
ParseClient::initialize(<my Parse keys>);
$query = new ParseQuery("Products");
$results = $query->find();
return array('products' => $results);
}
}
If instead of returning $results I return other dummy data, like return array('products' => 'fooProducts'), I no longer get the error message.
Also if I make a var_dump of the $results variable, I get the expected array of ParseObjects.
Here is my routing.yml file in case there is something wrong with it:
api:
resource: "#FooApiBundle/Controller/"
type: annotation
prefix: /
users:
type: rest
resource: Foo\ApiBundle\Controller\UsersController
products:
type: rest
resource: Foo\ApiBundle\Controller\ProductsController
By the error message it seems that the problem is related to Doctrine, but since I'm not using it, I don't know exactly how there can be a conflict or how to fix it. Any suggestions?
There are a few DocBlock typos of #returns in the Parse\ParseFile class that is causing Doctrine's Annotations class to attempt to identify them as a class. This is not your fault but a bug in the Parse PHP SDK library.
I've made a fix in this commit and submitted a pull request back to the original devs, so it should be a simple matter of eventually running composer update to bring your Parse library to the latest correct version.
You can read more about DocBlock and the part specifically on Annotations here
Here is a copy/paste of the resulting diff for src/Parse/ParseFile.php:
## -31,7 +31,7 ## class ParseFile implements \Parse\Internal\Encodable
/**
* Return the data for the file, downloading it if not already present.
*
- * #returns mixed
+ * #return mixed
*
* #throws ParseException
*/
## -50,7 +50,7 ## public function getData()
/**
* Return the URL for the file, if saved.
*
- * #returns string|null
+ * #return string|null
*/
public function getURL()
{
## -112,7 +112,7 ## public function getMimeType()
* #param string $name The file name on Parse, can be used to detect mimeType
* #param string $mimeType Optional, The mime-type to use when saving the file
*
- * #returns ParseFile
+ * #return ParseFile
*/
public static function createFromData($contents, $name, $mimeType = null)
{
## -132,7 +132,7 ## public static function createFromData($contents, $name, $mimeType = null)
* #param string $name Filename to use on Parse, can be used to detect mimeType
* #param string $mimeType Optional, The mime-type to use when saving the file
*
- * #returns ParseFile
+ * #return ParseFile
*/
public static function createFromFile($path, $name, $mimeType = null)
{
The correct way to initialize Parse using Symfony, is on the setContainer method of your controller:
class BaseController extends Controller
{
....
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer( $container );
ParseClient::initialize( $app_id, $rest_key, $master_key );
}
}
Depending of your needs, you can create a BaseController and extend it in your rest of controllers.
class UsersController extends Controller
In addition, you could add your keys in the parameters.yml file.
parameters:
#your parameters...
ParseAppId: your_id
ParseRestKey: your_rest_key
ParseMasterKey: your_master_key
TIP: Note you can add have different Parse projects (dev and release
version). Add your parameters in your different parameters
configuration provides an easy way to handle this issue.
class BaseController extends Controller
{
....
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer( $container );
$app_id = $container->getParameter('ParseAppId');
$rest_key = $container->getParameter('ParseRestKey');
$master_key = $container->getParameter('ParseMasterKey');
ParseClient::initialize( $app_id, $rest_key, $master_key );
}
}

Extending form validation in Codeigniter

I have placed this class file called 'My_Form_validation.php' into 'application/core' and I have also tried placing it in 'application/libraries'.
In my controller I am using
$this->form_validation->set_rules('user_postcode', 'Postcode', 'valid_postcode|trim|required|xss_clean');
This is whats in My_Form_validation.php - the actual logic is not in question here because I have a couple of options to actually validate the postcode. What I need help with is understanding why it is not loading or getting called!
My CI version is
define('CI_VERSION', '2.0.2');
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Form validation for UK Postcodes
*
* Check that its a valid postcode
* #author James Mills <james#koodoocreative.co.uk>
* #version 1.0
* #package FriendsSavingMoney
*/
class MY_Form_validation extends CI_Form_validation
{
function __construct()
{
parent::__construct();
log_message('debug', '*** Hello from MY_Form_validation ***');
}
function valid_postcode($postcode)
{
/**
*
* UK Postcode validation expression from Wikipedia
* http://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom
*
* Note: Remember to strtoupper() your postcode before inserting into database!
*
*/
$pattern = "/^(GIR 0AA)|(((A[BL]|B[ABDHLNRSTX]?|C[ABFHMORTVW]|D[ADEGHLNTY]|E[HNX]?|F[KY]|G[LUY]?|H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]?|M[EKL]?|N[EGNPRW]?|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKLMNOPRSTY]?|T[ADFNQRSW]|UB|W[ADFNRSV]|YO|ZE)[1-9]?[0-9]|((E|N|NW|SE|SW|W)1|EC[1-4]|WC[12])[A-HJKMNPR-Y]|(SW|W)([2-9]|[1-9][0-9])|EC[1-9][0-9]) [0-9][ABD-HJLNP-UW-Z]{2})$/";
if (preg_match($pattern, strtoupper($postcode)))
{
return TRUE;
}
else
{
$this->set_message('valid_postcode', 'Please enter a valid postcode');
return FALSE;
}
}
}
Because you're extending a CodeIgniter library and not a core component, you want to place that in application/libraries (not application/core).
And of course, don't forget to load the Form_validation library within your controller code.
$this->load->library('form_validation');
Other things to check:
Filename case sensitivity (MY_Form_validation.php loads while My_Form_validation.php won't)
Class name case sensitivity (class MY_Form_validation extends CI_Form_validation)
Reference material:
Extending Core Classes
Extending Native Libraries
You have to add $rules on your __construct method and also pass this to parent constructor
eg:
function __construct($rules = array())
{
parent::__construct($rules);
}
Look at Form_validation and provide same variables.