My website is build with flow 3.1.1
I have a class Employee with several simple properties (like name, birthday, etc.) and a property ‘teams’.
Property ‘teams’ holds a collection of Team instances and is declared like this
/**
* The teams an employee belongs to
*
* @var \Doctrine\Common\Collections\Collection<Aoe\Core\Domain\Model\Team>
* @ORM\ManyToMany(targetEntity="\Aoe\Core\Domain\Model\Team", mappedBy="employees")
* @ORM\OrderBy({"name" = "ASC"})
* @Flow\IgnoreValidation()
* @Flow\Lazy
*/
protected $teams;
There is also an customized object validator for Employee that ensures that at least one Team is assigned to the Employee.
Assuming during creation of a new Employee instance the only field not filled in is the ‘teams’ field then all properties are validated correctly and an error occures. The errorAction in employeeController forwards to the referring method as expected.
But as soon as ‘teams’ is filled in correctly and the field ‘name’ (or any other field) is missing the errorAction does not forward to the referring method anymore. Instead a flow error is thrown which includes all errors.
I guess it’s related to the doctrine annotation …cascade={“persist”}… cause the error is throwen in TYPO3\Flow\Persistence\Doctrine\PersistenceManager::validateObject(). It looks like instance Team trys to persist the invalid instance of class Employee. But of course validation fails…
Did anyone face a similar behaviour. Any hint or idea is appreciated
is a signal which is connected to a closure in \TYPO3\Flow\Package.
$dispatcher->connect(\TYPO3\Flow\Mvc\Dispatcher::class, 'afterControllerInvocation', function ($request) use ($bootstrap) {
if ($bootstrap->getObjectManager()->hasInstance(\TYPO3\Flow\Persistence\PersistenceManagerInterface::class)) {
if (!$request instanceof Mvc\ActionRequest || $request->getHttpRequest()->isMethodSafe() !== true) {
$bootstrap->getObjectManager()->get(\TYPO3\Flow\Persistence\PersistenceManagerInterface::class)->persistAll();
} elseif ($request->getHttpRequest()->isMethodSafe()) {
$bootstrap->getObjectManager()->get(\TYPO3\Flow\Persistence\PersistenceManagerInterface::class)->persistAll(true);
}
}
});
This final call to persistAll() causes an error in the persistence layer which I can not catch anymore
How could I avoid this persistAll() call at this point as here all validation is allready done and FLOW should redirect to a given Action?? Any help is grateful appreciated.
Validation effectively happens two times. Once in the controller, that’s the point were you want to act. The second time it happens in persist, this is to ensure data integrity before finally saving to DB. At this point you cannot interact, the exception will happen if validation fails. You need to make sure that the data validates at this point. So for some reason the first validation is not triggered or does not fail.
The question is why that happens and here I can only guess.
To debug check: \TYPO3\Flow\Mvc\Controller\ActionController::callActionMethod
and specifically the line $validationResult = $this->arguments->getValidationResults();
That’s the validation that should fail.
Maybe with some more input I can have more ideas about what is going wrong there.
all expected errors are properly caught at this point and a few lines below the errorAction is called.
if ($shouldCallActionMethod) {
$actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
} else {
$actionResult = call_user_func(array($this, $this->errorMethodName)); <--- is called
}
which is the default errorAction from TYPO3\Flow\Mvc\Controller\AbstractController. Following it’s method calls you end up in TYPO3\Flow\Mvc\Controller\AbstractController–>forwardToReferringRequest()
At this point the $referringRequest->getControllerActionName() returns the correct action (in this case ‘new’) and the forwarding should do fine. Next Step is the TYPO3\Flow\Mvc\Controller\AbstractController–>forward() method which throws an ForwardException
$this->arguments->removeAll();
$forwardException = new \TYPO3\Flow\Mvc\Exception\ForwardException();
$forwardException->setNextRequest($nextRequest);
throw $forwardException;
In this Signal emitAfterControllerInvocation() the persistAll() method is called and leads to an validation error in persistence layer which prevents the code requesting the newAction().
The final error is thrown in TYPO3\Flow\Persistence\Doctrine\PersistenceManager–>validateObject() method.
I figured out that the persistAll() call at this place is there since ever and probably makes sense. What is wrong is the fact that your object is registered for being persisted. Actually the action (in which you do something like $tihs->fooRepository->update($object)) should never be called as validation failed. That means persistAll should have nothing to persist. Apparently the object is registered for persistence at some other place but I don’t know exactly where. Do you have any other repository->update or persistenceManager->update calls?
That gave me the proper hint! There was indeed a teamRepository->update() call in the Employee class that caused the error. Ironically I never ran into that method during debugging.