Bug #65472
closedTYPO3 6.2.10 Extbase Type Converter can't resolve Tx_Extbase_Persistence_ObjectStorage
0%
Description
Upgrading from 6.2.9 to 6.2.10 extbase fails to save values in frontend editing forms (standard f:form and f:input, f:select, ... fields with object / property binding, using standard repository methods add / update) to work on properties defined like this:
/** * Some Variable * * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Someextension_Domain_Model_Somedata> * @lazy */ protected $someVariable;
results in this on saving:
Uncaught TYPO3 Exception #1297759968: Exception while property mapping at property path "someVariable":Class Tx_Extbase_Persistence_ObjectStorage<Tx_Someextension_Domain_Model_Somedata> does not exist (More information) TYPO3\CMS\Extbase\Property\Exception thrown in file /.../typo3_src-6.2.10/typo3/sysext/extbase/Classes/Property/PropertyMapper.php in line 106.
Similar error like it was fixed in #54289. Probably got re-introduced by the new class loading mechanism in 6.2.10 that seems not to be able to work in this case on not-namespaces classes with the rewritten extbase property manager and the object binding in frontend forms.
Switching core back to 6.2.9 and clearing all caches, my forms save their data with no problem.
If of any importance my CF config looks like this:
'caching' => array( 'cacheConfigurations' => array( 'cache_pages' => array( 'options' => array( 'compression' => TRUE, ), ), 'extbase_object' => array( 'backend' => '\\TYPO3\\CMS\\Core\\Cache\\Backend\\NullBackend', ), 'extbase_reflection' => array( 'backend' => '\\TYPO3\\CMS\\Core\\Cache\\Backend\\NullBackend', ), ), ),
Updated by Helmut Hummel over 9 years ago
- Status changed from New to Needs Feedback
I tried to reproduce with extension news by changing the property like that:
/** * @var Tx_Extbase_Persistence_ObjectStorage<Tx_News_Domain_Model_News> * @lazy */ protected $related;
It worked like expected.
Please provide a minimal code example on how to reproduce the error you are seeing.
Updated by Matthias Krappitz over 9 years ago
Controller Code:
/** * action edit * * @param Tx_Someextension_Domain_Model_CompanyProfile $companyProfile * @return void */ public function editAction($companyProfile) { $accessControlService = $this->objectManager->get('Tx_Someextension_Service_AccessControlService'); if ($accessControlService->hasLoggedInFrontendUser()) { // ... $this->view->assign('companyProfile', $companyProfile); $this->view->assign('sectorOptions', $this->sectorRepository->findAll()); } } // ensuring the minimum fields field in current foreign language public function initializeUpdateAction () { $ensureOverlayFieldsFilled = array('title', 'address', 'city'); $languages = array(1, 2); foreach ($languages as $language) { foreach ($ensureOverlayFieldsFilled as $field) { if (trim($_REQUEST['tx_someextension_someextension']['overlay'][$language][$field]) == '') { // ... } } } } /** * action update * * @param Tx_Someextension_Domain_Model_CompanyProfile $companyProfile * @return void */ public function updateAction(Tx_Someextension_Domain_Model_CompanyProfile $companyProfile) { $accessControlService = $this->objectManager->get('Tx_Someextension_Service_AccessControlService'); if ($accessControlService->hasLoggedInFrontendUser()) { ... $this->companyProfileRepository->update($companyProfile); ... $this->flashMessageContainer->add( Tx_Extbase_Utility_Localization::translate('your_data_has_been_saved', $this->extensionName), NULL, t3lib_Flashmessage::OK ); $this->redirect('edit', NULL, NULL, array('companyProfile' => $companyProfile->getUid())); } }
Model
class Tx_Someextension_Domain_Model_CompanyProfile extends Tx_Extbase_DomainObject_AbstractEntity { // ... /** * Sectors * * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Someextension_Domain_Model_Sector> * @lazy */ protected $sectors; // ... /** * __construct * * @return void */ public function __construct() { //Do not remove the next line: It would break the functionality $this->initStorageObjects(); } /** * Initializes all Tx_Extbase_Persistence_ObjectStorage properties. * * @return void */ protected function initStorageObjects() { /** * Do not modify this method! * It will be rewritten on each save in the extension builder * You may modify the constructor of this class instead */ $this->sectors = new Tx_Extbase_Persistence_ObjectStorage(); // ... } // ... /** * Adds a Sector * * @param Tx_Someextension_Domain_Model_Sector $sector * @return void */ public function addSector(Tx_Someextension_Domain_Model_Sector $sector) { $this->sectors->attach($sector); } /** * Removes a Sector * * @param Tx_Someextension_Domain_Model_Sector $sectorToRemove The Sector to be removed * @return void */ public function removeSector(Tx_Someextension_Domain_Model_Sector $sectorToRemove) { $this->sectors->detach($sectorToRemove); } /** * Returns the sectors * * @return Tx_Extbase_Persistence_ObjectStorage<Tx_Someextension_Domain_Model_Sector> $sectors */ public function getSectors() { return $this->sectors; } /** * Sets the sectors * * @param Tx_Extbase_Persistence_ObjectStorage<Tx_Someextension_Domain_Model_Sector> $sectors * @return void */ public function setSectors(Tx_Extbase_Persistence_ObjectStorage $sectors) { $this->sectors = $sectors; } }
Repository
class Tx_Somextension_Domain_Repository_CompanyProfileRepository extends Tx_Extbase_Persistence_Repository { /** * defaultOrderings * * @var array */ protected $defaultOrderings = array( 'profiletype' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING, 'crdate' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING, ); /** * initializeObject * * @info necessary because of fundamental language overlay handling change in 6.2 * @return void */ public function initializeObject() { $defaultQuerySettings = $this->createQuery()->getQuerySettings(); $defaultQuerySettings->setRespectSysLanguage(FALSE); if ($GLOBALS['TSFE']->sys_language_uid) { $defaultQuerySettings->setSysLanguageUid($GLOBALS['TSFE']->sys_language_uid); } $this->setDefaultQuerySettings($defaultQuerySettings); } // ... }
Edit Template
<f:flashMessages renderMode="div" /> <f:render partial="FormErrors" arguments="{_all}"/> <f:form action="update" name="companyProfile" enctype="multipart/form-data" object="{companyProfile}"> ... <f:form.select property="sectors" options="{sectorOptions}" optionValueField="uid" optionLabelField="title" multiple="true" size="8" /> ... <f:render partial="Form/RequiredNotice" /> <f:render partial="Form/Submit" arguments="{buttonText: 'save'}" /> </f:form>
Error stacktrace
Uncaught TYPO3 Exception #1297759968: Exception while property mapping at property path "sectors":Class Tx_Extbase_Persistence_ObjectStorage<Tx_Someextension_Domain_Model_Sector> does not exist (More information) TYPO3\CMS\Extbase\Property\Exception thrown in file /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Property/PropertyMapper.php in line 106. 16 TYPO3\CMS\Extbase\Property\PropertyMapper::convert(array, "Tx_Someextension_Domain_Model_CompanyProfile", TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration) /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Mvc/Controller/Argument.php: 00372: return $this; 00373: } 00374: $this->value = $this->propertyMapper->convert($rawValue, $this->dataType, $this->propertyMappingConfiguration); 00375: $this->validationResults = $this->propertyMapper->getMessages(); 00376: if ($this->validator !== NULL) { 15 TYPO3\CMS\Extbase\Mvc\Controller\Argument::setValue(array) /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Mvc/Controller/AbstractController.php: 00421: $argumentName = $argument->getName(); 00422: if ($this->request->hasArgument($argumentName)) { 00423: $argument->setValue($this->request->getArgument($argumentName)); 00424: } elseif ($argument->isRequired()) { 00425: throw new \TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException('Required argument "' . $argumentName . '" is not set.', 1298012500); 14 TYPO3\CMS\Extbase\Mvc\Controller\AbstractController::mapRequestArgumentsToControllerArguments() /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php: 00148: call_user_func(array($this, $actionInitializationMethodName)); 00149: } 00150: $this->mapRequestArgumentsToControllerArguments(); 00151: $this->checkRequestHash(); 00152: $this->controllerContext = $this->buildControllerContext(); 13 TYPO3\CMS\Extbase\Mvc\Controller\ActionController::processRequest(TYPO3\CMS\Extbase\Mvc\Web\Request, TYPO3\CMS\Extbase\Mvc\Web\Response) /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Mvc/Dispatcher.php: 00067: $controller = $this->resolveController($request); 00068: try { 00069: $controller->processRequest($request, $response); 00070: } catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $ignoredException) { 00071: } 12 TYPO3\CMS\Extbase\Mvc\Dispatcher::dispatch(TYPO3\CMS\Extbase\Mvc\Web\Request, TYPO3\CMS\Extbase\Mvc\Web\Response) /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Mvc/Web/FrontendRequestHandler.php: 00054: /** @var $response \TYPO3\CMS\Extbase\Mvc\ResponseInterface */ 00055: $response = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Response'); 00056: $this->dispatcher->dispatch($request, $response); 00057: return $response; 00058: } 11 TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler::handleRequest() /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Core/Bootstrap.php: 00193: $requestHandler = $requestHandlerResolver->resolveRequestHandler(); 00194: 00195: $response = $requestHandler->handleRequest(); 00196: // If response is NULL after handling the request we need to stop 00197: // This happens for instance, when a USER object was converted to a USER_INT 10 TYPO3\CMS\Extbase\Core\Bootstrap::handleRequest() /.../www/typo3_src-6.2.10/typo3/sysext/extbase/Classes/Core/Bootstrap.php: 00182: public function run($content, $configuration) { 00183: $this->initialize($configuration); 00184: return $this->handleRequest(); 00185: } 00186: 9 TYPO3\CMS\Extbase\Core\Bootstrap::run("", array) 8 call_user_func_array(array, array) /is/htdocs/wp1148156_S2ZW3VJZ68/www/typo3_src-6.2.10/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php: 06620: $content, 06621: $conf 06622: )); 06623: } else { 06624: $GLOBALS['TT']->setTSlogMessage('Method "' . $parts[1] . '" did not exist in class "' . $parts[0] . '"', 3); ...
Updated by Matthias Krappitz over 9 years ago
Maybe this also of importance: I have registered an additional typeconverter to allow NULL values on object properties:
ext_localconf.php
Tx_Extbase_Utility_Extension::registerTypeConverter('Tx_Someextension_Property_TypeConverter_PersistentObjectConverter');
Type Converter Class
class Tx_Someextension_Property_TypeConverter_PersistentObjectConverter extends Tx_Extbase_Property_TypeConverter_PersistentObjectConverter { /** * Set this to a higher value then the core has, * * @var integer */ protected $priority = 2; /** * Call core functionality. * If an exception rises up, check whether it's because the parameter was not a valid uid. * Then check whether it's null and return null or let the exception pass. * * @param mixed $identity * @param string $targetType * @return object * @author Daniel Siepmann <daniel.siepmann@wfp2.com> */ protected function fetchObjectFromPersistence($identity, $targetType) { try { return parent::fetchObjectFromPersistence($identity, $targetType); } catch (Exception $e) { if ($e->getCode() === 1297931020 && is_string($identity) && (strtolower($identity) === 'null' || $identity === '' || $identity === NULL)) { return NULL; } throw $e; } } }
But error remains even with this Typeconverter disabled.
Updated by Matthias Krappitz over 9 years ago
You can close this one. This error is gone with 6.2.11. So it was a regression of the new class loading mechanism.
Updated by Riccardo De Contardi over 9 years ago
- Status changed from Needs Feedback to Closed
close as per request of the reporter.