Symfony2: transactions fail with "There is no active transaction." - symfony

I've spend several hours trying to resolve this issue. Google and Stackoverflow didn't help much either. So any advice is most welcome here.
I'm trying to apply a rollback logic with transactions when updating two tables in relation:
The code in general is:
// ...
$em = $this->getDoctrine()->getEntityManager();
$em->getConnection()->beginTransaction();
foreach($dataArr as $data) {
$userObj = $em->getRepository('AcmeBundle:User')->find($userId);
$userObj->setActive(1);
$em->persist($userObj);
$em->getConnection()->commit();
}
$storeObj = $em->getRepository('AcmeBundle:Store')->find($storeId);
$storeObj->setIsOpen(1);
$em->persist($storeObj);
$em->getConnection()->commit();
try {
$em->flush();
$em->clear();
} catch(Exception $e) {
$em->getConnection()->rollback();
$em->close();
throw $e;
}
My PDO drivers are enabled, updating without transactions works as expected, but once I beginTransaction() and try to commit() nothing works and I get the There is no active transaction. exception.
Some sources suggested using only commit() without persist() but it doesn't make any difference. I'm probably doing something really stupid here, but I just cannot see what it is.

After
$this->em->getConnection()->beginTransaction();
you must write:
$this->em->getConnection()->setAutoCommit(false);
It works for me :)

I once accidentally got this error
by doing following:
$em->getConnection()->beginTransaction();
try {
$em->persist($entityA);
$em->flush();
$em->persist($entityB);
$em->flush();
$em->getConnection()->commit();
//exception thrown here
$mailer->send($from, $to, $subject, $text);
} catch (\Exception($ex)) {
$em->getConnection()->rollback();
}
So, you already have guessed that there should not be any code after commit as in the case when this arbitary code($mailer service in our example) throws an exception transaction would be closed before the moment catch block is executed. Maybe this will save a minute or two to somebody:)

Since the version 1.5.2 of DoctrineBundle, you can configure the connection to use auto_commit in the configuration of your project.
# app/config/config.yml (sf2-3) or config/doctrine.yaml (sf4)
doctrine:
dbal:
auto_commit: false

As #prodigitalson correctly suggested I needed to do a commit() before the flush() in order for the get the queries executed. So the working code now is:
$em = $this->getDoctrine()->getEntityManager();
$em->getConnection()->beginTransaction();
foreach($dataArr as $data) {
$userObj = $em->getRepository('AcmeBundle:User')->find($userId);
$userObj->setActive(1);
$em->persist($userObj);
// this is no longer needed
// $em->getConnection()->commit();
}
$storeObj = $em->getRepository('AcmeBundle:Store')->find($storeId);
$storeObj->setIsOpen(1);
$em->persist($storeObj);
// this is no longer needed
// $em->getConnection()->commit();
try {
// Do a commit before the FLUSH
$em->getConnection()->commit();
$em->flush();
$em->clear();
} catch(Exception $e) {
$em->getConnection()->rollback();
$em->close();
throw $e;
}

Related

Catch the Process Timeout RuntimeException

In my project, I use the ProcessCompoment and I use a timeout of 120 seconds.
$process->setTimeout(120);
$process->run();
// executes after the command finishes
if (!$process->isSuccessful()) {
$job->setResult('error');
} else {
$job->setResult($process->getOutput());
}
The problem is, when the timeout is reached Symfony return a RuntimeException, but I need to know when this command is aborted, to store an error in place of the result in my database.
Someone have an idea ?
Finally I just use a simple try-catch...
$process->setTimeout(120);
try {
$process->run();
} catch (RuntimeException $exception) {
$job->setResult('error');
}

Silex - my error handler isn't working

I am trying to set up a error handler on my controller to catch anything that might cause my page to malfunction. For example: in this scenario I am trying to catch any error that could possibly happen once my method calls a external API with a bad parameter but it doesn't seem to do anything except give me the typical ClientException in Middleware.php line 69:
Client error: 400 which isn't what I am exactly aiming for. Any advice will be greatly be appreciated or better ways of handling errors in Silex.
private function getSIS($url, $session, Application $app)
{
$message = "You don't have permission to access this!";
if($app['security']->isGranted('ROLE_SUPER_ADMIN'))
{
$client = new Client(['base_uri' => 'https://***********.ca/api/SIS/']);
if (!empty($session))
$response = $client->get($url, ['query' => 'session=' . $session]);
else
$response = $client->get($url);
return $response;
}
$app->error(function (\Exception $e, $code) {
switch($code) {
case 404:
$message = 'The requested page could not be found';
break;
default:
$message = 'We are sorry, but something went terribly wrong.';
}
return new Response($message);
});
return new Response($message);
}
The $app->error method might need to be placed outside the context of your controller actions. I'm not sure exactly how you have your application structured but maybe try placing the error block right before $app->run();
$app->error(function (\Exception $e, $code) use ($app) {
switch($code) {
case 404:
$message = 'The requested page could not be found';
break;
default:
$message = 'We are sorry, but something went terribly wrong.';
}
return new Response($message, $code);
});
$app->run();

Calling VoiceCommandDefinitionManager Causes Thread Execution to Stop

I'm totally at a loss. When I call either:
var a = VoiceCommandDefinitionManager.InstalledCommandDefinitions;
OR
await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager
.InstallCommandDefinitionsFromStorageFileAsync( storageFile );
Execution of the thread ends inside either call.
For example, in the following method after calling InstallCommandDefinitionsFromStorageFilesAsync nothing happens. No exception, no write lines, no execution after calling that method.
private async void RegisterVoiceCommands()
{
var storageFile =
await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync( new Uri( "ms-appx:///VoiceCommandDefinition.xml" ) );
try
{
await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync( storageFile );
Debug.WriteLine( "Voice Commands Registered" );
}
catch ( Exception ex )
{
Debug.WriteLine( ex );
}
}
Does anyone have any ideas? This used to work in the Technical Preview.
ENVIRONMENT:
Win 10 Enterprise
VS2015 Enterprise
So it turns out in my case it's a machine issue. The project works correctly on every other box I tried it on. Bad install I guess.

Symfony2 Doctrine - Flushing in kernel.response listener flushs bad data

In order to do some logging for my Symfony2 app, I created a service that logs any connection, here is the method called on kernel.response :
public function log(FilterResponseEvent $event)
{
$log = new Log();
$request = $event->getRequest();
$response = $event->getResponse();
//fill the Log entity with stuff from request & response data
$manager = $this->container->get('doctrine.orm.entity_manager');
$manager->persist($log);
$manager->flush();
}
All of this seems fine, however when I execute a test like this one (patch with empty data to trigger a failure):
$this->client->request(
'PATCH',
'/users/testificate',
array(
'firstName' => '',
)
);
Which calls this action :
protected function processForm($item, $method = 'PATCH')
{
$form = $this->createForm(new $this->form(), $item, array('method' => $method));
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
$response = new Response();
// Set the `Location` header only when creating new resources
if ($method == 'POST') {
$response->setStatusCode(201);
$response->headers->set('Location',
$this->generateUrl(
'get_' . strtolower($class), array('slug' => $item->getId()),
true // absolute
)
);
}
else {
$response->setStatusCode(204);
}
$this->em->flush();
return $response;
}
$this->em->detach($item);
return RestView::create($form, 400);
}
Although the test fails, the entity is patched, and of course it must not.
After some search what I've learnt is:
The parameters enter the form validator
The validation fails, thus returning a 400 http code without flushing the entity
However during the validation process, the entity gets hydrated with the invalid data
When the service is called on kernel.response, the $manager->flush(); flush all the data... including the bad data provided by the PATCH test.
What I've tried thus far:
1) Do a $manager->clear(); before $manager->persist(); ... doesn't change anything
2) Do a $manager->detach($item); if the form validation failed... doesn't change anything
Thanks !
I recently stumbled across problems with flushing in kernel.response when upgrading from Doctrine 2.3.4 to the latest 2.4 branch. Try flusing the log entities from kernel.terminate. Leave any modifications to the Response in kernel.response.

symfony 2 error - persisting data to a database

I get a message : "Oops! An Error Occurred
The server returned a "500 Internal Server Error".
Something is broken. Please e-mail us at [email] and let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused" when persisting data to a database. Here is a controller:
public function registerAction()
{
$register = new Register();
$form = $this->createForm(new RegisterType(), $register);
$request = $this->getRequest();
if ($request->getMethod() == 'POST')
{
$form->bindRequest($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getEntityManager();
$em->persist($register);
$em->flush();
return $this->redirect($this->generateUrl('ShopMyShopBundle_register'));
}
}
return $this->render('ShopMyShopBundle:Main:register.html.twig', array('form' => $form->createView()));
}
Where is the problem ?
The code you provided is not enough to find the reason. You should develop using the dev environment to see detailed error messages. To do it, access your app with the app_dev.php front controller. See the section on environments.

Resources