Project

General

Profile

Actions

Bug #61628

open

PropertyMappingConfiguration for ObjectStorages / Arrays

Added by André Wuttig over 9 years ago. Updated over 8 years ago.

Status:
New
Priority:
Should have
Assignee:
-
Category:
Extbase
Target version:
-
Start date:
2014-09-16
Due date:
% Done:

0%

Estimated time:
TYPO3 Version:
6.2
PHP Version:
Tags:
Complexity:
hard
Is Regression:
No
Sprint Focus:

Description

Hi,

i want to create different type of objects from fluid within a form. Within the initializeCreateAction() i do this here:

$propertyMappingConfiguration->forProperty('newsletters.*')->allowAllProperties();         

$propertyMappingConfiguration->forProperty('newsletters.*')->setTypeConverterOption('TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED,TRUE);

In the view i write this code:

<f:for each="{newsletters}" as="newsletter">
            <f:form.hidden property="newsletters.{newsletter.listId}.__type" value="{newsletter.type}" />
            <f:form.checkbox id="newsletter-{newsletter.listId}" property="newsletters.{newsletter.listId}.listId" value="{newsletter.listId}" />
            <label for="newsletter-{newsletter.listId}">Sign up to our newsletter?</label>
        </f:for>

The Problem is, that the propertyMapping wildcard doesnt work for arrays!?


Related issues 1 (1 open0 closed)

Related to TYPO3 Core - Bug #75231: PropertyMapper fails for Demand-Object like objectsNew2016-03-22

Actions
Actions #1

Updated by Stefan Froemken over 9 years ago

Hello André,

I'm wondering about this one. You're working with the original Fluid-ViewHelpers for form elements. So there is no need to explicit allow creation of these subproperties. Further all subproperties will be added to __trustedProperties if you're using fluid VHs. So for now I don't understand your problem. Please control HTML-Output. Maybe there was something rendered wrong.

Stefan

Actions #2

Updated by Alexander Opitz over 9 years ago

  • Status changed from New to Needs Feedback
Actions #3

Updated by André Wuttig over 9 years ago

@Stefan Froemken

So there is no need to explicit allow creation of these subproperties.

This is not correct. If i do not allow CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED or CONFIGURATION_CREATION_ALLOWED for the childobjects of the newsletter list extbase will throw an exception:

 Exception while property mapping at property path "newsletters.0":Override of target type not allowed. To enable this, you need to set the PropertyMappingConfiguration Value "CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED" to TRUE.

more details here: http://wiki.typo3.org/Exception/CMS/1297759968

my current solution is a hack within the initializeAction. I iterate from 0-99 to set the propertyMapping for 99 items and hope that there are not more than this.


        for ($i = 0; $i < 99; $i++) {
            $propertyMappingConfiguration->forProperty('newsletters.' . $i)->setTypeConverterOption(
                'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
                PersistentObjectConverter::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED,
                TRUE
            );
            $propertyMappingConfiguration->forProperty('newsletters.' . $i)->setTypeConverterOption(
                'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
                TRUE
            );
            $propertyMappingConfiguration->forProperty('newsletters.' . $i)->setTypeConverterOption(
                'TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter',
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED,
                TRUE
            );
        }


Actions #4

Updated by Alexander Opitz over 9 years ago

  • Status changed from Needs Feedback to New
Actions #5

Updated by Pascal Dürsteler over 8 years ago

This is still the case in 7.x.. Example:

public function initializeAction() {
    $propertyMappingConfiguration = $this->arguments['foo']->getPropertyMappingConfiguration();
    $propertyMappingConfiguration
        ->forProperty('bar.*')
        ->allowProperties('beginOn');
    $propertyMappingConfiguration
        ->forProperty('bar.0.beginOn') // This does work, but doing 'bar.*.beginOn' is not working
        ->setTypeConverterOption(
            'TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter',
            \TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter::CONFIGURATION_DATE_FORMAT,
            'd.m.Y'
    );
}
Actions #6

Updated by Mathias Brodala over 8 years ago

The reason for this is that the PropertyMappingConfiguration will always use the specific configuration for a property path if set. This is always the case with forms sent via Fluid. Even if you set additional configuration for the placeholder path (aka wildcard), that configuration is never considered.

One solution to this could be changing the logic of the various methods in PropertyMappingConfiguration to always check for configuration for the placeholder path in case no specific configuration for the given property path was found. This could be seen as more or less breaking change. Turning this behavior off could also prove tricky.

Actions #7

Updated by Stefan Froemken over 8 years ago

The problem: If you create formfields, extbase don't know, if they are allowed or not. It's up to you to define this information for each property on your own.

The solution: Fluids FormViewHelpers knows all formfields (created with f:form.*) you have implemented. With help of renderTrustedPropertiesField() it renders a hidden textfield with all allowed formfields allowed for next request in serialized format.
The ActionController has a method called initializePropertyMappingConfigurationFromRequest() where we have a foreach over all trustedProperties. If one of the properties are also required by your ActionMethod this property and/or DomainModel-properties will all get a standardized PropertyMapperConfiguration, where we save the information that this property is allowed for current request.
If you add a formfield without f:form.* it will not be inserted in trustedProperties, will not get a PropertyMapperConfiguration and extbase will fail with an Exception: Property is not allowed.

No problem with fixed relations:
You have a form where you build up a 1:N relation like person:email. Each person can only have a maximum of 5 emails. You build these 5 emailfields with f:form.*. Fluid will render the correct trustedProperties for person.email.[0-4].mailAddress. There is no need to explicit allow the subproperties.

A little problem with variable relations:
You have a form where you build up a 1:N relation like person:email. It's up to the person to define how many email addresses he will declaire. You build ONE emailfields with f:form.* and if the visitor clicks on a JavaScript-Button you copy the rendered emailform and change the name attribute. Fluid will render trustedProperties ONLY for first emailfield, because it was builded by f:form.*. All dynamically created fields (the copy) are unknown to fluid and you have to modify PropertyMappingConfiguration on your own with: $propertyMappingConfiguration->forProperty('email.*')->allowProperties('mailAddress');

What happens in extbase?
The first email is allowed, because there is the PropertyMappingConfiguration coming from trustedProperties: person.email.0.emailAddress. For sure there is also our PropertyMappingConfiguration for person.email.*.emailAddress, but Configurations with a matching key (in our case 0) have priority. For further emails there is no matching key and * comes into process.

Good to know:
With each call to forProperty() you automatically create a new PropertyMappingConfiguration for all properties in your path

The problem with typeConverters:
You have a form where you build up a 1:N relation like company:employees. It's up to the employer to add one or more employees to his company. So we have same like above. We build a basic employee form with f:form.* and create a JavaScript Button to create a copy of this form and increase the name-attribute on each copy. Fluid adds the formfields of our FIRST employee to trustedProperties. Further copied employees are unknown. It's up to you to allow further Employees in initializeCreateAction() with forProperty('company.employees.*')->allowProperties('firstName', 'lastName', 'dateOfBirth', ...). An employee has a birthday. So you add following to your Configuration:

setTypeConverterOption(
    'TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter',
    \TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter::CONFIGURATION_DATE_FORMAT,
    'd.m.Y'
);

OK, what will happen in Extbase?
The PropertyMapper will get the first employee (index key is 0). He will find the automatically created PropertyMappingConfiguration of Fluid, which was created with help of the trustedProperties. This is because it has a higher index than our Configuration with *. So PropertyMapper will NOT find our configuration how to convert a string to DateTime and extbase will fail with an Exception.

So, what can you do?
As long as you don't need TypeConvertes you're happy with methods like forProperty() and allowProperties(). If you need TypeConverter for properties in a 1:N relation you have to build your form fields on your own. Without f:form.*! All sub-properties are now unknown. So no standardized PropertyMappingConfiguration can be builded by extbase. Now you can create your own * Configuration which no has priority and your form works again.

Actions

Also available in: Atom PDF