andreas andreas - 25 days ago 7
PHP Question

Update Domain Model except for one property in TYPO3 6.2

I maintain a TYPO3 extension that manages frontend users in the backend. Therefore I extend the FrontendUserRepository with my own model. My extension provides CRUD operations and I have a problem with updating the password of existing persons. The idea is to only update the password, if the password field in the edit form is filled, otherwise (if it's left empty) the old password value remains in the database.

Now everything was working fine with TYPO3 4.5, but now after I upgraded to 6.2, an empty string is saved to the database when submitting the edit form with an empty password field...

This is my

updateAction()
:

/**
* action update
*
* @param \My\Vendor\Domain\Model\Person $person
*
* @return void
*/
public function updateAction(\My\Vendor\Domain\Model\Person $person) {
// only hash and set password if not empty
if ($person->getPassword() == '') {
// if password was left empty, get current password from database
$oldPerson = $this->personRepository->findByUid($person->getUid());
$person->setPassword($oldPerson->getPassword()));
} else {
$person->setPassword(md5($person->getPassword()));
}

// save updated person to repository
$this->personRepository->update($person);

$this->flashMessageContainer->add('The person data was saved.');
$this->redirect('edit', NULL, NULL, array('person' => $person));
}


Does anybody know, why
$oldPerson->getPassword()
does not return the current value for the password field from the database? Or is there another way to "skip" a property of a domain model while updating all other properties? The strange thing is that it worked in TYPO3 4.5 ...

Answer

Does anybody know, why $oldPerson->getPassword() does not return the current value for the password field from the database?

This is because Extbase has a kind of 1st level cache: if the object was fetched form persistence once, it will not be fetched second time from database during same request, but returned directly form a memory.

So, in your case $person object is fetched from database 1st time, when a property mapping happens (internal Extbase operation which translates your POST data to instance of \My\Vendor\Domain\Model\Person).

When you call $this->personRepository->findByUid($person->getUid()); Extbase doesn't make a database lookup, but fetches object directly form memory resulting in $oldPerson === $person. And since $person has already changed password (via POST data), $oldPerson->getPassword() returns also the changed value.

Possible solution for this is to get clean property

If the property of model was changed but not yet saved there is almost always a possibility to fetch the original value (e.g. one, that exists in db). You can use a _getCleanProperty($propertyName) method of model for this:

$person->setPassword($oldPerson->_getCleanProperty('password')));

Optionally if you don't even want a db update of password field, you can even memorize clean property state, which will tell Extbase: do not update the property in db:

$person->_memorizePropertyCleanState('password');

Note: after you memorize property state, _getCleanProperty() will return the value, which was set by set*() method - not the original one present in db (in case you set a differnet value).