Zend framework complains that "There is already an active transaction" - mysql

we are using zend_db_table and we are having some issues since Zend Framework is complaining about two transactions being active:
[message:protected] => There is already an active transaction
[string:Exception:private] =>
[code:protected] => 0
[file:protected] => /var/www/vhosts/test.local/private/library/Zend/Db/Adapter/Pdo/Abstract.php
[line:protected] => 305
[trace:Exception:private] => Array
This is the code in the Controller:
public function convertAction()
{
$this->setNoRender();
// If the quote is a copy of a previous one, fetch all the datas
$quoteId = Zend_Filter::filterStatic($this->getRequest()->getParam('qte_id'), 'int');
$quoteTable = new Model_QuotesTable();
$quoteRow = $quoteTable->findById($quoteId);
if (count($quoteRow)) {
$clonedId = $quoteRow->convertToJob();
$this->flashMessageRedirect('Quotation successfully converted', '/jobs/edit/job_id/' . $clonedId);
} else {
$this->flashMessageRedirect('Unable to find the quote to be converted', '/quotes');
}
}
which is recalling this function in QuotesTableRow which extends zend_db_table_abstract:
public function convertToJob()
{
$db = $this->_getTable()->getAdapter();
$db->beginTransaction();
$jobsTable = new Model_JobsTable();
try {
/*
* Update the status of the old row to match the $status passed into this function
*/
$this->qte_status = "Accepted";
$this->save();
/*
* Create new row with the same details as above
*/
$newRow = $jobsTable->createRow();
$newRow->job_title = $this->qte_title;
$newRow->job_cus_id = $this->qte_cus_id;
$newRow->job_enq_id = $this->qte_enq_id;
$newRow->job_qte_id = $this->qte_id;
$newRow->job_title = $this->qte_title;
$newRow->job_description = $this->qte_description;
$newRow->job_work_location_id = $this->qte_work_location_id;
$newRow->job_work_category_id = $this->qte_work_category_id;
$newRow->job_work_type_id = $this->qte_work_type_id;
$newRow->job_cus_code = $this->qte_cus_code;
$newRow->job_cus_name = $this->qte_cus_name;
$newRow->job_wt_ref_code = $this->qte_wt_ref_code;
$newRow->job_wt_description = $this->qte_wt_description;
$newRow->job_wl_code = $this->qte_wl_code;
$newRow->job_wl_description = $this->qte_wl_description;
$newRow->job_wc_ref_code = $this->qte_wc_ref_code;
$newRow->job_wc_description = $this->qte_wc_description;
$newRow->job_qte_title = $this->qte_title;
$newRow->job_datetime_created = date('Y-m-d H:i:s');
$newRowId = $newRow->save();
$db->commit();
return $newRowId;
}
catch (Exception $e) {
$db->rollback();
echo('<pre>');
print_r($e);
echo('</pre>');
exit();
throw new Exception($e->getMessage());
return false;
}
}
in addition, it seems to be related to the model we are not in since if we comment the row with the save() function related to the Model_JobsTable() the script is working, while it returns the same error when we comment the other save().

This error is being returned from MySQL and ZF is only telling you the error message.
Are you starting two transactions in the same request? That can explain why you got this error message, or you could have had an aborted connection that was in the middle of a transaction and it didn't get rolled back or auto-committed.
You should only start one transaction per database connection. If you need two models to have an active transaction in a single request, then you need to get 2 separate database connections.
See this (great) answer by Bill Karwin in regards to this issue.
You can run the query SHOW ENGINE InnoDB STATUS; to get a list of active transactions. If you have one that is open and you have no active transactions from PHP/ZF, then try closing that transaction, otherwise you'll have to look into your code and see how two transactions are getting started in the same request.

Thanks for your answer, we found a solution.
The problem was that, we were using the save() function twice; changing the first save() with an insert(), solved the problem:
public function convertToJob()
{
$db = $this->_getTable()->getAdapter();
$db->beginTransaction();
$jobsTable = new Model_JobsTable();
try {
/*
* Create new row with the same details as above
*/
$data = array(
'job_cus_id' => $this->qte_cus_id,
'job_enq_id' => $this->qte_enq_id,
'job_qte_id' => $this->qte_id,
'job_title' => $this->qte_title,
'job_description' => $this->qte_description,
'job_work_location_id' => $this->qte_work_location_id,
'job_work_category_id' => $this->qte_work_category_id,
'job_work_type_id' => $this->qte_work_type_id,
'job_cus_code' => $this->qte_cus_code,
'job_cus_name' => $this->qte_cus_name,
'job_wt_ref_code' => $this->qte_wt_ref_code,
'job_wt_description' => $this->qte_wt_description,
'job_wl_code' => $this->qte_wl_code,
'job_wl_description' => $this->qte_wl_description,
'job_wc_ref_code' => $this->qte_wc_ref_code,
'job_wc_description' => $this->qte_wc_description,
'job_qte_title' => $this->qte_title,
'job_datetime_created' => date('Y-m-d H:i:s')
);
$newRowId = $jobsTable->insert($data);
/*
* Update the status of the old row to match the $status passed into this function
*/
$this->qte_status = "Accepted";
$this->save();
$db->commit();
return $newRowId;
}
catch (Exception $e) {
throw new Exception($e->getMessage());
return false;
}
}

Related

New record and many to many insert

I am working in a project where the users have a rate plan associated. When a new user is created, a valid rate plan must be specified.
I have the following MySQL schema and Eloquent models:
/**
* User Eloquent model file ...
*
*/
public function ratePlans() {
return $this->belongsToMany(
'App\Models\RatePlan',
'users_rate_plans',
'users_id',
'rate_plans_id'
);
}
So, to create a new user with your selected rate plan i do:
try {
\DB::beginTransaction();
$model->create($data);
$model->ratePlans()->attach($data['rate_plan'], ['active' => 1]);
\DB::commit();
return $model;
} catch(\Exception $e) {
\DB::rollback();
return false;
}
But, i am getting the next exception:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column
'users_id' cannot be null (SQL: insert into users_rate_plans
(active, rate_plans_id, users_id) values (1, 43, ))
Why te transaction didn't work ? How i can do that task ?
UPDATE 1
I changed the transaction code but, the result is the same.
try {
\DB::beginTransaction();
$ratePlan = \App\Models\RatePlan::find($data['rate_plan']);
$user->ratePlans()->attach($ratePlan, ['active' => 1]);
$user->create($data);
\DB::commit();
return $user;
} catch(\Exception $e) {
\DB::rollback();
die($e->getMessage());
return false;
}
UPDATE 2
I changed the transaction code again and its works:
\DB::beginTransaction();
$user = \App\Models\User::create($data);
$ratePlan = \App\Models\RatePlan::find($data['rate_plan']);
$user->ratePlans()->attach($ratePlan, ['active' => 1]); \DB::commit();
return $user;
I think you're not loading the rate_plans entity.
$model->ratePlans()->attach($data['rate_plan'], ['active' => 1]);
In this line $data['rate_plan'] shoud be an instance of your model "rate_plans", and I'm assuming that $model in this situation stand for an entity of your User model
Also have tried a test without the transaction if the result's is the same ?
I give you an example of one of my code which is similar:
try {
DB::beginTransaction();
$group = Group::create($data);
$employees = User::whereIn('reference', $references)->get();
$group->employees()->attach($employees);
$group->save();
DB::commit();
} catch(Exception $e) { [...] }
Good luck

Base Table not found on unique value validation in MongoDB with laravel

I'm using laravel 5.3 with jenssegers/laravel-mongodb package for managing mongodb connections.
I want to check every time a user send a request to register a website in my controller if it's unique then let the user to register his/her website domain.
I wrote below code for validation but What I get in result is :
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'iranad.seat' doesn't exist (SQL: select count(*) as aggregate from `seat` where `domain` = order.org)
my controller code :
public function store(Request $request) {
$seat = new Seat();
$validator = Validator::make($request->all(), [
'domain' => 'required|regex:/^([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/|unique:seat', //validating user is entering correct url like : iranad.ir
'category' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->messages(), 400);
} else {
try {
$statusCode = 200;
$seat->user_id = Auth::user()->id;
$seat->url = $request->input('domain');
$seat->cats = $request->input('category');
$seat->filter = [];
if($request->input('category') == 'all') {
$obj['cats'] = 'false';
$seat->target = $obj;
} else {
$obj['cats'] = 'true';
$seat->target = $obj;
}
$seat->status = 'Waiting';
$seat->save();
} catch (\Exception $e) {
$statusCode = 400;
} finally {
$response = \Response::json($seat, $statusCode);
return $response;
}
}
}
My Seat Model :
namespace App;
use Moloquent;
use Carbon\Carbon;
class Seat extends Moloquent {
public function getCreatedAtAttribute($value) {
return Carbon::createFromTimestamp(strtotime($value))
->timezone('Asia/Tehran')
->toDateTimeString();
}
}
Obviously The validator is checking if domain is unique in mysql tables which causes this error, How can I change my validation process to check mongodb instead of mysql ?
I solved the problem, The solution is that you should add Moloquent to your model and define database connection :
namespace App\Models;
use Moloquent;
use Carbon\Carbon;
class Seat extends Moloquent
{
protected $collection = 'seat';
protected $connection = 'mongodb';
}

Save into multiple tables using stored procedure

I have 2 models: ReceivedGoodsDetail and StockInventory.
When model ReceivedGoodsDetail do actionCreate then StockInventory automatically also will be inserted into table StockInventory.
I use this stored procedure, this what I've tried:
public function actionCreate($id) {
$model = new ReceivedGoodsDetail();
$connection = \Yii::$app->db;
$transaction = $connection->beginTransaction();
$model->ID_Received_Goods = $id;
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$connection = Yii::$app->db;
$command = $connection->createCommand('{call usp_T_Received_Goods_Detail#InsertData(:ID_Received_Goods,:ID_Item, :Qty, :User)}');
$ID_Received_Goods = $model->ID_Received_Goods;
$ID_Item = $model->ID_Item;
$Qty = $model->Qty;
$User = Yii::$app->user->identity->username;
$command->bindParam(":ID_Received_Goods",$ID_Received_Goods,PDO::PARAM_STR);
$command->bindParam(":ID_Item", $ID_Item, PDO::PARAM_STR);
$command->bindParam(":Qty", $Qty, PDO::PARAM_INT);
$command->bindParam(":User", $User, PDO::PARAM_STR);
if ($command->execute() == 0) {
$transaction->commit();
} else {
$transaction->rollBack();
foreach ($model->getErrors() as $key => $message) {
Yii::$app->session->setFlash('error', $message);
}
}
return $this->redirect(['receivedgoodsheader/view', 'id' => $model->ID_Received_Goods]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
But I'm confused if use 2 models like the case above
Do not be afraid to do such things, here is nothing bad to use stored procedures. But in general your code is not clean and pretty confusing.
First of all, if you are using stored procedure, then why do not make a trigger for ReceivedGoodsDetail (on INSTERT)? IMHO everything will be much simpler with trigger.
Here are some remarks for your implementation.
Why do you open transaction before first if? If validation fails then your transaction will not be closed
manually.
I cant't see here using of 2 models, just one - ReceivedGoodsDetail, and StockInventory
as i can understand will be created in stored procedure usp_T_Received_Goods_Detail#InsertData?
Why do you redirect user to the item view even if transaction fails?
Using ActiveRecord. Then here is no need to start transaction manually. Just define what operations
you wish to be transactional for this model in transactions() method.
Using ActiveRecord. It is better practice to get db connection from your model class, not application.
It will be Yii::$app->db by default, but later you can easily change connection for this particular model.
It will be better for you (for example) to extend ActiveRecord (if not yet) and overload insertInternal() method
for ReceivedGoodsDetail.
In class ReceivedGoodsDetail:
public function transactions() {
return [
'default' => self::OP_INSERT
];
}
protected function insertInternal($attributeNames = null) {
if (!$this->beforeSave(true)) {
return false;
}
$values = $this->getDirtyAttributes($attributes);
/* overrided part of code */
$connection = static::getDb();
$command = $connection->createCommand('{call usp_T_Received_Goods_Detail#InsertData(:ID_Received_Goods,:ID_Item, :Qty, :User)}');
$ID_Received_Goods = $model->ID_Received_Goods;
$ID_Item = $model->ID_Item;
$Qty = $model->Qty;
$User = Yii::$app->user->identity->username;
$command->bindParam(":ID_Received_Goods",$ID_Received_Goods,PDO::PARAM_STR);
$command->bindParam(":ID_Item", $ID_Item, PDO::PARAM_STR);
$command->bindParam(":Qty", $Qty, PDO::PARAM_INT);
$command->bindParam(":User", $User, PDO::PARAM_STR);
if($command->execute() != 0) {
return false;
}
/* end of overrided part */
$changedAttributes = array_fill_keys(array_keys($values), null);
$this->setOldAttributes($values);
$this->afterSave(true, $changedAttributes);
return true;
}
In your action:
public function actionCreate($id) {
$model = new ReceivedGoodsDetail();
$model->ID_Received_Goods = $id;
if ($model->load(Yii::$app->request->post()) && $model->save(true)) {
return $this->redirect(['receivedgoodsheader/view', 'id' => $model->ID_Received_Goods]);
} else {
foreach ($model->getErrors() as $key => $message) {
Yii::$app->session->setFlash('error', $message);
}
return $this->render('create', [
'model' => $model,
]);
}
}
And then catch your flash messages on create form.
P.S. One more moment. It is strange practice to use path/to/model/{id} endpoint
with predefined ID to create new instance. Usually this looks like POST path/to/model. But this can be subject of your business logic, so i don't know if it can be improved or not
P.P.S. This example was not tested (obviously) so here can be some mistakes

'Cannot create an empty shipment' while trying to create shipment in magento

I am trying to create shipment and adding tracking number after placing an order,but i am getting an error like Cannot create an empty shipment. when i search through google i got one of the reason for this is item quantity is null, but what i used below is returning the exact quantities of products ordered.
$itemQty = $order->getItemsCollection()->count();
I don't know exactly it is only the reason for that error. what i done mistake? anybody knows please help me on this.
public function salesOrderInvoiceShipmentCreate($observer)
{
// $order = $observer->getEvent()->getOrder();
//$order = Mage::getModel('sales/order')->loadByIncrementId($orderId);
$order_id = $observer->getData('order_ids');
$order = Mage::getModel('sales/order')->load($order_id);
$token = '3acb6561b04117c6cbe3552c90f1d6815507e257';
$waybill_url = 'https://track.delhivery.com/waybill/api/fetch/json/?token='.$token.'&cl=GEECHOO';
$waybill = file_get_contents($waybill_url);
Mage::log($order, Zend_Log::INFO, 'order.log', true);
if (!$order->getId()) {
Mage::throwException('Order does not exist, for the Shipment process to complete');
}
if ($order->canShip()) {
try {
// $shipment = Mage::getModel('sales/service_order', $order)
// ->prepareShipment($this->_getItemQtys($order));
$itemQty = $order->getItemsCollection()->count();
$shipment = Mage::getModel('sales/service_order', $order)->prepareShipment($itemQty);
$shipmentCarrierCode = '';
$shipmentCarrierTitle = '';
$arrTracking = array(
'carrier_code' => isset($shipmentCarrierCode) ? $shipmentCarrierCode : $order->getShippingCarrier()->getCarrierCode(),
'title' => isset($shipmentCarrierTitle) ? $shipmentCarrierTitle : $order->getShippingCarrier()->getConfigData('title'),
'tracking_number' => $waybill,
);
$track = Mage::getModel('sales/order_shipment_track')->addData($arrTracking);
$shipment->addTrack($track);
// Register Shipment
$shipment->register();
// Save the Shipment
$this->_saveShipment($shipment, $order);
// Finally, Save the Order
$this->_saveOrder($order);
} catch (Exception $e) {
throw $e;
}
}
}
Try this for order item quantity
$quote = Mage::helper('checkout/cart')->getCart()->getQuote();
$value = [];
foreach ($quote->getAllItems() as $item) {
$value[]= array (
'id' => $item->getSku(),
'quantity' => $item->getQty(),
}

How to avoid the instruction "return" inside a function in Symfony2?

I would like to know how to avoid the instruction "return" inside a function in Symfony2. In other words how can I make a void function which doesn't return anything. In fact I have tried that for a long time but every time I run the code I did I see this error message: "The controller must return a response" ... By the way, this is the code that I have:
public function AddeventsgroupeAction(Request $request) {
$eventg = new eventsgroupe();
$form = $this->createForm(new eventsgroupeType(), $eventg);
$em = $this->getDoctrine()->getManager();
$securityContext = $this->get('security.context');
$token = $securityContext->getToken();
$user = $token->getUser();
$id = $user->getId();
$groupe=$this->getRequest('groupe');
$idg = intval($groupe->attributes->get('id'));
$qb = $em->createQueryBuilder();
$qb->select('l')
->from('IkprojGroupeBundle:Groupe', 'l')
->from('IkprojGroupeBundle:eventsgroupe', 'e')
->where(' l.id = :g and e.idGroupe = l.idAdmin and l.id = e.idEventGroupe');
$qb->setParameter("g", $idg);
$query = $qb->getQuery();
$res = $query->getResult();
$rows = array();
foreach ($res as $obj) {
$rows[] = array(
'id' => $obj->getId());
}
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$eventg-> setIdGroupe($id);
$eventg-> setIdEventGroupe($idg);
$em->persist($eventg);
$em->flush();
return $moslem="yes";
}
} else {
return $this->render('IkprojGroupeBundle:GroupeEvents:Addeventgroupe.html.twig', array(
'groupe' => $rows,
'event' => $eventg,
'form' => $form->createView(),
));
}
}
How can I replace the instruction : return $moslem="yes"; in order to not return anything??...Is that possible??
To answer your basic question, a simple return will return a void from your function.
The "controller must return a response" message actually comes from the request handler. You need to tell the request handler what you want it to do. There is no default page so a void return will trigger the error.
In most cases, after successfully processing a posted form you will want to return a redirect response.
Something like:
$form->handleRequest($request);
if ($form->isValid()) {
...
$em->flush();
return $this->redirect($this->generateUrl('task_success'));
I should point out that your form code seems to be from S2.1 or older. It's unnecessarily complicated. You should be using at least 2.3. Make sure you are looking at the correct version of the documentation. Hint: the isValid() takes care of the POST check.
http://symfony.com/doc/current/book/forms.html#handling-form-submissions
It's also worth while to understand the request/response workflow.
http://symfony.com/doc/current/book/http_fundamentals.html
Digging into the code can also help in understanding where the error message is coming from:
Symfony\Component\HttpKernel\HttpKernel#handleRaw($request)
Simple, delete the else statement and if $request->isMethod('POST') or $form->isValid() returns false the code inside will not be executed then the script return the default view.
EDIT: you can also make a redirect with a flash message where needed like this:
$this->get('session')->getFlashBag()->add('success', 'your success message');
return $this->redirect($this->generateUrl('your_route'));
Remember to add support for flash message in your view looking at the Symfony2 docs