TYPO3 f:form with additional arguments, where submit not update the arguments - typo3

I am using TYPO3 10.4.15
My edit view:
f:section name="content">
<h1>Edit Album</h1>
<f:flashMessages />
<f:render partial="FormErrors" />
<f:form id='fNew' action="update" name="album" object="{album}" arguments="{mode:mode, disc:disc}" >
<f:render partial="Album/FormFields" arguments="{album:album, disc:disc}" />
<f:form.submit value="Save" />
</f:form>
</f:section>
</html>
This is the relevant part of the partial formfields.html:
<f:if condition='{disc}'>
<input type='text' name="disc[0][name][]" />
</f:if>
The error_log with the disc structure looks:
Update-Disc: array (
0 =>
array (
'name' => '',
'trackNum' => '1',
'track' =>
array (
0 =>
array (
'title' => '',
'duration' => '0',
'composer' => '',
'texter' => '',
'musicFile' => '',
'imageFile' => '',
),
),
),
)
And this is the "updateAction" part of the controller
/**
* action update
*
* #param \HGA\Album\Domain\Model\Album $album
* #param string $mode
* #param array $disc
* #return string|object|null|void
*/
public function updateAction(\HGA\Album\Domain\Model\Album $album, $mode, $disc)
{
error_log("Update-Disc: " . var_export($disc, true) . " Mode: " . $mode, 0);
if ($mode == 'tracks') {
$this->editAction($album, $mode, $disc);
}
error_log("Update: " . var_export($album, true) . " Mode: " . $mode, 0);
$this->addFlashMessage('The object was updated. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/typo3cms/extensions/extension_builder/User/Index.html', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
$this->albumRepository->update($album);
$this->redirect('list');
}
If I write something into the text input field and execute submit, I get the error_log you can see above. The value I have typed in the input field is missing. It is only the array, as I have send it to the view.
The mode string will be transmitted correctly, but with the disc array is maybe something wrong!
The disc array is more complex, but I made it simple, because I need to understand how it works in general.
I also need this additional disc array and can not doing it with the album object!
Thanks in advance for your help.

You are ignoring your plugin's namespace in combination with misinterpretation of f:form arguments.
Each field for your plugin has a prefix like tx_hgaalbum... followed by your property's name in square brackets. So the fieldname for disc should look like tx_hgaalbum...[disc]. Have a look into the HTML code and see which names are generated for the other properties.
The second problem is using the arguments in the form-ViewHelper. This will only add the arguments to the action URI of your form. That's why you're getting your initial values for disc.

Related

Extbase Property Mapping for arrays

I want to use a Array Object inside a Fluid form using Property Mapper. The products are dynamic added if user clicks an "add_product" link:
<f:form action="property" name="newOrder" object="{newOrder}">
<f:for each="{newOrder.orderProduct}" as="orderProduct" iteration="iterator">
<f:form.hidden property="orderProduct.{iterator.index}.product" value="8" />
<h3>OrderProduct: {orderProduct.product.title}</h3>
</f:for>
<f:form.hidden name="add_product" value="1" />
<input type="submit" value="submit" />
</f:form>
What I get after submit is this exception.
Uncaught TYPO3 Exception #1297759968:
Exception while property mapping at property path "orderProduct.0":
Property "product" was not found in target object of type "MyVendor\MyShop\Domain\Model\Product".
The hidden field resolves to: <input name="tx_myshop_pi1[newOrder][orderProduct][0][product]" value="8" type="hidden"> (the static value of 8 is just to simplify the example)
I also tried key="key" instead of iterator, empty brackets orderProduct[], using name instead of property without result.
This is the (simplified) Debug output:
newOrder (MyVendor\MyShop\Domain\Model\ShopOrder)
=> orderProduct (TYPO3\CMS\Extbase\Persistence\ObjectStorage)
3222112 => MyVendor\MyShop\Domain\Model\OrderProduct
product => MyVendor\MyShop\Domain\Model\Product
uid => 8
title => 'Product1'
This is the Model Code:
ShopOrder https://pastebin.com/YN7X37ei
OrderProduct https://pastebin.com/zFyztLAQ
For the Property Mapper, I tried a lot of configurations without success. In my opinion this should work but it does not:
public function initializePropertyAction()
{
/** #var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
$propertyMappingConfiguration = $this->arguments['newOrder']->getPropertyMappingConfiguration();
$propertyMappingConfiguration->allowAllProperties();
$propertyMappingConfiguration->setTypeConverterOption('TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE);
$propertyMappingConfiguration->forProperty('orderProduct')->allowAllProperties();
$propertyMappingConfiguration->forProperty('orderProduct')->setTypeConverterOption(
'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE
);
//workaround from https://forge.typo3.org/issues/61628
for ($i = 0; $i < 99; $i++) {
$propertyMappingConfiguration->forProperty('orderProduct.' . $i)->allowAllProperties();
$propertyMappingConfiguration->forProperty('orderProduct.' . $i . '.*')->allowAllProperties();
$propertyMappingConfiguration->forProperty('orderProduct.' . $i)->setTypeConverterOption(
'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE
);
}
}
I solved it like this, in my case for a question with a dynamic number of answers having two fields, each:
$propertyMappingConfiguration = $this->arguments->getArgument('question')->getPropertyMappingConfiguration();
$propertyMappingConfiguration->skipProperties('category');
$propertyMappingConfiguration->allowProperties('answers');
$propertyMappingConfiguration->forProperty('answers.*')->allowProperties('answerField1', 'answerField2');
$propertyMappingConfiguration->allowCreationForSubProperty('answers.*');
$propertyMappingConfiguration->allowModificationForSubProperty('answers.*');

How to use checkboxes with Phalcon forms?

I am creating a form using Phalcon that has a checkbox on it. I use this code to create the checkbox in my PagesForm.php file
$this->add(new Check('usesLayout'));
and then in my view I have
{{ form.render("usesLayout") }}
However, if the checkbox is unchecked then Phalcon complains about usesLayout is required.
The html code produced by the view is
<input type="checkbox" id="usesLayout" name="usesLayout" value="1" checked="checked" />
What is the correct way to create a Phalcon form with a checkbox so that it accepts it both checked and unchecked?
Desired outcome
After looking back at a form made when using CakePHP the html output is
<input type="hidden" name="usesLayout" id="usesLayout_" value="0" />
<input type="checkbox" name="usesLayout" id="usesLayout" value="1" checked="checked" />
This works fine, so I am looking for something similar to this.
Current Workaround
After modifying the code in the final response to this question I have this workaround currently (I use this instead of Phalcon\Forms\Element\Check)
namespace Armaware\InBrowserDev\Forms\Element;
use Phalcon\Forms\Element\Check as PhalconCheck;
class Check extends PhalconCheck
{
/**
* Renders the element widget returning html
*
* #param array|null $attributes Element attributes
*
* #return string
*/
public function render($attributes = null)
{
$attrs = array();
if (!is_null($attributes)) {
foreach ($attributes as $attrName => $attrVal) {
if (is_numeric($attrName) || in_array($attrName, array('id', 'name', 'placeholder'))) {
continue;
}
$attrs[] = $attrName .'="'. $attrVal .'"';
}
}
$attrs = ' '. implode(' ', $attrs);
$id = $this->getAttribute('id', $this->getName());
$name = $this->getName();
$checked = '';
if ($this->getValue()) {
$checked = ' checked';
}
return <<<HTML
<input type="hidden" id="{$id}_" name="{$name}" value="0" />
<input type="checkbox" id="{$id}" name="{$name}" value="1"{$attrs}{$checked} />
HTML;
}
}
public Phalcon\Forms\ElementInterface setDefault (unknown $value) inherited from Phalcon\Forms\Element
Sets a default value in case the form does not use an entity or there is no value available for the element in _POST
Source.
Looks like your declaration of form can look like this:
$controls[] = (new Check('usesLayout', ['value' => '1']))
->setLabel('Should I use layout?')
->setDefault('0') // or `false` in case it's not filtered
->addFilter('bool'); // filtering to boolean value
Not tested, but probably will do. You can always try to make this trick with handling this in beforeValidation() method of form, but have no space to test it right now and am not risking on failurable solution here.

Retrieving values of Form::select

I have a select box with an array of data to populate it like this:
{!! Form::select('language',$languageArray,'null', ['id'=>'language','multiple',]) !!}
I am passing $languageArray with view , and is simply an array of values like ['A','B','C']...
Now while fetching the selected values i am getting numeric value of selected options. Is there a way to change the values from numeric indexes to Text written in option. i did it using an associative array as second argument like this:
['english' => 'English',
'french' => 'French',
'so on ...' => 'So On ..']
But it creates a long list and view seems to be overloaded with data is there a better way for achieving below output ???
<select name="language">
<option value="english" ">English</option>
<option value="french">French</option>
....
I suggest you to use Config values ,
Create a file like languages.php in config folder.
<?php
return ['english' => 'English',
'french' => 'French',
'so on ...' => 'So On ..'
'german' => Lang::get('languages.german')
];
View :
{!! Form::select('language',Config::get('languages'),'null', ['id'=>'language','multiple',]) !!}
As you can see, in this way you can use config values in another view too and support multi language(its important too.. look at 'german')
Last Option is creating your own Form macro for example,
Form::macro('slugiySelect', function($name , $list , $selected = null , $options = [])
{
$options = [];
foreach($list as $row)
$options[Str::slug($row)] = $row;
return Form::select($name , $options , $selected , $options);
});
In this macro your options array is slugify with Laravel string function and uses as a key , I kept value as yours. You can do it with your way.

Symfony 2 This form should not contain extra fields

I created a form using formBuilder in Symfony. I add some basic styling to the form inputs using an external stylesheet and referencing the tag id. The form renders correctly and processes information correctly.
However, it outputs an unwanted unordered list with a list item containing the following text: This form should not contain extra fields.
I am having a really hard time getting rid of this notice. I was wondering if someone can help me understand why it being rendered with my form and how to remove it?
Many thanks in advance!
Controller
$form = $this->createFormBuilder($search)
->add('searchinput', 'text', array('label'=>false, 'required' =>false))
->add('search', 'submit')
->getForm();
$form->handleRequest($request);
Twig Output (form is outputted and processed correctly
This form should not contain extra fields.
Rendered HTML
<form method="post" action="">
<div id="form">
<ul>
<li>This form should not contain extra fields.</li>
</ul>
<div>
<input type="text" id="form_searchinput" name="form[searchinput]" />
</div>
<div>
<button type="submit" id="form_search" name="form[search]">Search</button>
</div>
<input type="hidden" id="form__token" name="form[_token]" value="bb342d7ef928e984713d8cf3eda9a63440f973f2" />
</div>
</form>
It seems to me that you have the problem because of the token field. If it is so, try to add options to createFormBuilder():
$this->createFormBuilder($search, array(
'csrf_protection' => true,
'csrf_field_name' => '_token',
))
->add('searchinput', 'text', array('label'=>false, 'required' =>false))
->add('search', 'submit')
->getForm();
To find out the extra field use this code in controller, where you get the request:
$data = $request->request->all();
print("REQUEST DATA<br/>");
foreach ($data as $k => $d) {
print("$k: <pre>"); print_r($d); print("</pre>");
}
$children = $form->all();
print("<br/>FORM CHILDREN<br/>");
foreach ($children as $ch) {
print($ch->getName() . "<br/>");
}
$data = array_diff_key($data, $children);
//$data contains now extra fields
print("<br/>DIFF DATA<br/>");
foreach ($data as $k => $d) {
print("$k: <pre>"); print_r($d); print("</pre>");
}
$form->bind($data);
This message is also possible if you added/changed fields in your createFormBuilder() and press refresh in your browser...
In this case it's ok after sending the form again ;-)
I got the same message while having multiple forms on the same page. Turns out, symfony defaults to the name 'form' for all of them. Instead of using createFormBuilder, you can change the name of the form to avoid conflicts using
public FormBuilderInterface createNamedBuilder(string $name, string|FormTypeInterface $type = 'form', mixed $data = null, array $options = array(), FormBuilderInterface $parent = null)
See https://stackoverflow.com/a/13366086/1025437 for an example.
I ran into this error when creating a multi-step form.
When the step 1 form is submitted, $request->request contains acme_mybundle_myform array. This created a validation error and stopped the back, forward and form fields from populating correctly. Not to mention "this-form-should-not-contain-extra-fields"
I discovered this thanks to the code by nni6.
The solution in my case was inside the controller:
if ($form->isValid())
{
if($form->has('nextStep') && $form->get('nextStep')->isClicked())
{
$session->getFlashBag()->set('notice', 'Next clicked');
$registerType->incrementStep();
$request->request->remove('acme_mybundle_myform');
return $this->forward("AcmeMyBundle:Default:register", array($request));
}
....
}
I had the same error.
It was because I had a form which, by mistake, had a NULL name.
In the HTML, the name attribute would look like this:
<form name href="..." action"..."></form>
As simple as that.
Might not be the case for everyone, but worth to check.

Typo3 backend module form error

I have no idea why, but the error just disappear without any changes. Now it works. I have not change anything. (I deleted cache many times so it cannot be because of the cache)
Problem
I created an extension using extension builder (if anyone knows any good documentation please give me link because official documentation does not have any examples).
I have a form and when I submit the form I have the error
TYPO3 v4.7
The action "formSave" (controller "Promoters") is not allowed by this plugin. Please check Tx_Extbase_Utility_Extension::configurePlugin() in your ext_localconf.php.
I created ext_localconf.php according to typo's wiki.
Form code
<f:form action="formSave" name="" object="">
<f:form.textfield id="emailResendInterval" name="emailResendInterval" value="" />
<f:form.textarea cols="30" rows="5" id="emails" name="emails" value="" />
<f:form.submit name="submit" value="Save" />
</f:form>
ext_localconf.php
<?php
if (!defined ('TYPO3_MODE')) die ('Access denied.');
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$_EXTKEY] = unserialize($_EXTCONF);
if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$_EXTKEY]['registerSinglePlugin']) {
// fully fletged blog
Tx_Extbase_Utility_Extension::configurePlugin(
$_EXTKEY, // The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
'Promoters', // A unique name of the plugin in UpperCamelCase
array ( // An array holding the controller-action-combinations that are accessible
'Promoters' => 'configuration,formSave', // The first controller and its first action will be the default
),
array( // An array of non-cachable controller-action-combinations (they must already be enabled)
)
);
} else {
Tx_Extbase_Utility_Extension::configurePlugin(
$_EXTKEY, // The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
'Promoters', // A unique name of the plugin in UpperCamelCase
array ( // An array holding the controller-action-combinations that are accessible
'Promoters' => 'configuration,formSave', // The first controller and its first action will be the default
),
array( // An array of non-cachable controller-action-combinations (they must already be enabled)
)
);
PromotersControler
class Tx_Promoters_Controller_PromotersController extends Tx_Extbase_MVC_Controller_ActionController {
/**
* action configuration
*
* #return void
*/
public function configurationAction() {
}
/**
* action formSave
*
* #return void
*/
public function formSaveAction() {
}
}
Seems fine actually, I'm not sure about the if statemant in the localconf though. Please try this:
<?php
if (!defined ('TYPO3_MODE')) die ('Access denied.');
// fully fletged blog
Tx_Extbase_Utility_Extension::configurePlugin(
$_EXTKEY,
'Promoters',
array (
'Promoters' => 'configuration,formSave',
),
array(
)
);
?>