Skip to content

Commit

Permalink
try to fix problems with db transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcMichalsky committed Mar 19, 2024
1 parent 9c9259e commit 4c9235c
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 45 deletions.
73 changes: 41 additions & 32 deletions Civi/Twingle/Shop/BAO/TwingleProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

namespace Civi\Twingle\Shop\BAO;

use Civi\Api4\PriceField;
use Civi\Twingle\Shop\DAO\TwingleProduct as TwingleProductDAO;
use Civi\Twingle\Shop\DAO\TwingleShop as TwingleShopDAO;
use Civi\Twingle\Shop\Exceptions\ProductException;
use Civi\Twingle\Shop\Exceptions\ShopException;
use CRM_Core_Exception;
use CRM_Core_Transaction;
use CRM_Twingle_ExtensionUtil as E;
use CRM_Utils_Type;
use function Civi\Twingle\Shop\Utils\convert_int_to_bool;
Expand Down Expand Up @@ -86,6 +88,7 @@ class TwingleProduct extends TwingleProductDAO {
"twingle_shop_id",
"financial_type_id",
"price_field_id",
"project_id",
"external_id",
"tw_updated_at",
"tw_created_at",
Expand Down Expand Up @@ -306,15 +309,12 @@ public function createPriceField($mode = 'create') {
if ($mode == 'edit') {
$price_field_data['id'] = $this->price_field_id;
}

try {
$price_field = civicrm_api3('PriceField', 'create', $price_field_data);
if ($price_field['is_error'] != 0) {
throw new ProductException(
E::ts('Could not create PriceField for this Twingle Product: %1',
[1 => $price_field['error_message']]),
ProductException::ERROR_CODE_COULD_NOT_CREATE_PRICE_FIELD);
}
$price_field = civicrm_api4(
'PriceField',
'create',
['values' => $price_field_data],
)->first();
$this->price_field_id = (int) $price_field['id'];
}
catch (CRM_Core_Exception $e) {
Expand All @@ -341,21 +341,24 @@ public function createPriceField($mode = 'create') {
}

// Create PriceFieldValue
$price_field_value_data = [
'price_field_id' => $this->price_field_id,
'financial_type_id' => $this->financial_type_id,
'label' => $this->name,
'amount' => $this->price,
'is_active' => $this->is_active,
'description' => $this->description,
];
// Add id if in edit mode
if ($mode == 'edit' && $price_field_value) {
$price_field_value_data['id'] = $price_field_value['id'];
}
try {
$price_field_value_data = [
'price_field_id' => $this->price_field_id,
'financial_type_id' => $this->financial_type_id,
'label' => $this->name,
'amount' => $this->price,
'is_active' => $this->is_active,
'description' => $this->description,
];
// Add id if in edit mode
if ($mode == 'edit' && $price_field_value) {
$price_field_value_data['id'] = $price_field_value['id'];
}

civicrm_api3('PriceFieldValue', 'create', $price_field_value_data);
civicrm_api4(
'PriceFieldValue',
'create',
['values' => $price_field_value_data],
);
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
Expand Down Expand Up @@ -406,11 +409,16 @@ public static function findByExternalId($external_id) {
/**
* Add Twingle Product
*
* @param string $mode
* 'create' or 'edit'
* @return array
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
* @throws \Exception
*/
public function add() {
public function add($mode = 'create') {

$tx = new CRM_Core_Transaction();

// Try to lookup object in database
try {
$dao = TwingleShopDAO::executeQuery("SELECT * FROM civicrm_twingle_product WHERE external_id = %1",
Expand All @@ -425,26 +433,27 @@ public function add() {
ShopException::ERROR_CODE_COULD_NOT_FIND_SHOP_IN_DB);
}

// Define hook type
$hook = $this->id ? 'edit' : 'create';

// Register pre-hook
\CRM_Utils_Hook::pre($hook, 'TwingleProduct', $this->id);

// Create associated PriceField
$this->createPriceField($hook);
\CRM_Utils_Hook::pre($mode, 'TwingleProduct', $this->id);

// Set latest tw_updated_at as new updated_at
$this->updated_at = \CRM_Utils_Time::date('Y-m-d H:i:s', $this->tw_updated_at);

// Save object to database
$this->save();
try {
$this->save();
} catch (\Exception $e) {
$tx->rollback();
throw new ProductException(
E::ts('Could not save TwingleProduct to database: ' . $e->getMessage()),
ProductException::ERROR_CODE_COULD_NOT_CREATE_PRODUCT);
}
$result = self::findById($this->id);
/* @var self $result */
$this->load($result->getAttributes());

// Register post-hook
\CRM_Utils_Hook::post($hook, 'TwingleProduct', $this->id, $instance);
\CRM_Utils_Hook::post($mode, 'TwingleProduct', $this->id, $instance);

return $result->toArray();
}
Expand Down
16 changes: 7 additions & 9 deletions Civi/Twingle/Shop/BAO/TwingleShop.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,12 @@ function getAttributes(): array {
/**
* Add Twingle Shop
*
* @param string $mode
* 'create' or 'edit'
* @return array
* @throws \Civi\Twingle\Shop\Exceptions\ShopException
*/
public function add() {
public function add($mode = 'create') {

// Try to lookup object in database
try {
Expand All @@ -149,20 +151,14 @@ public function add() {
ShopException::ERROR_CODE_COULD_NOT_FIND_SHOP_IN_DB);
}

// Define hook type
$hook = $this->id ? 'edit' : 'create';

// Register pre-hook
\CRM_Utils_Hook::pre($hook, 'TwingleShop', $this->id);

// Create associated PriceSet
$this->createPriceSet($hook);
\CRM_Utils_Hook::pre($mode, 'TwingleShop', $this->id);

// Save object to database
$result = $this->save();

// Register post-hook
\CRM_Utils_Hook::post($hook, 'TwingleShop', $this->id, $instance);
\CRM_Utils_Hook::post($mode, 'TwingleShop', $this->id, $instance);

return $result->toArray();
}
Expand Down Expand Up @@ -310,6 +306,8 @@ public function getProducts() {
/**
* Creates Twingle Shop as a price set in CiviCRM.
*
* @param string $mode
* 'create' or 'edit'
* @throws \Civi\Twingle\Shop\Exceptions\ShopException
*/
public function createPriceSet($mode = 'create') {
Expand Down
2 changes: 1 addition & 1 deletion Civi/Twingle/Shop/Exceptions/ProductException.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ class ProductException extends BaseException {
public const ERROR_CODE_COULD_NOT_DELETE_PRICE_FIELD = 'price_field_deletion_failed';
public const ERROR_CODE_COULD_NOT_DELETE_PRICE_FIELD_VALUE = 'price_field_value_deletion_failed';
public const ERROR_CODE_PRICE_FIELD_STILL_EXISTS = 'price_field_still_exists';
public const ERROR_CODE_PRICE_FIELD_VALUE_STILL_EXISTS = 'price_field_still_exists';
public const ERROR_CODE_COULD_NOT_CREATE_PRODUCT = 'product_creation_failed';

}
8 changes: 7 additions & 1 deletion api/v3/TwingleProduct/Create.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,14 @@ function civicrm_api3_twingle_product_Create($params): array {
$product = new TwingleProduct();
$product->load($params);

// Define mode
$mode = $product->id ? 'edit' : 'create';

// Create associated PriceField
$product->createPriceField($mode);

// Save TwingleProduct
$product->add();
$product->add($mode);
$result = $product->getAttributes();
return civicrm_api3_create_success($result, $params, 'TwingleProduct', 'Create');
}
Expand Down
8 changes: 7 additions & 1 deletion api/v3/TwingleShop/Create.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ function civicrm_api3_twingle_shop_Create($params) {
$shop = new TwingleShop();
$shop->load($params);

// Define mode
$mode = $shop->id ? 'edit' : 'create';

// Create associated PriceSet
$shop->createPriceSet($mode);

// Save TwingleShop
$result = $shop->add();
$result = $shop->add($mode);

// Return success
return civicrm_api3_create_success($result, $params, 'TwingleShop', 'Create');
Expand Down
2 changes: 1 addition & 1 deletion sql/civicrm_twingle_shop.sql
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ CREATE TABLE `civicrm_twingle_product` (
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp of when the product was created in the database',
`updated_at` datetime NOT NULL COMMENT 'Timestamp of when the product was last updated in the Twingle database',
PRIMARY KEY (`id`),
CONSTRAINT FK_civicrm_twingle_product_price_field_id FOREIGN KEY (`price_field_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE CASCADE,
CONSTRAINT FK_civicrm_twingle_product_price_field_id FOREIGN KEY (`price_field_id`) REFERENCES `civicrm_price_field`(`id`) ON DELETE CASCADE,
CONSTRAINT FK_civicrm_twingle_product_twingle_shop_id FOREIGN KEY (`twingle_shop_id`) REFERENCES `civicrm_twingle_shop`(`id`) ON DELETE CASCADE
)
ENGINE=InnoDB;

0 comments on commit 4c9235c

Please sign in to comment.