Fix DAO/BAO namespaces and definitions

This commit is contained in:
Jens Schuppe 2024-09-11 12:59:22 +02:00
parent 7cca29b458
commit 64d6b48813
10 changed files with 41 additions and 77 deletions

View file

@ -0,0 +1,673 @@
<?php
use Civi\Api4\PriceField;
use Civi\Api4\PriceFieldValue;
use Civi\Twingle\Shop\Exceptions\ProductException;
use Civi\Twingle\Shop\Exceptions\ShopException;
use CRM_Twingle_ExtensionUtil as E;
use function Civi\Twingle\Shop\Utils\convert_int_to_bool;
use function Civi\Twingle\Shop\Utils\convert_str_to_date;
use function Civi\Twingle\Shop\Utils\convert_str_to_int;
use function Civi\Twingle\Shop\Utils\convert_empty_string_to_null;
use function Civi\Twingle\Shop\Utils\filter_attributes;
use function Civi\Twingle\Shop\Utils\validate_data_types;
require_once E::path() . '/Civi/Twingle/Shop/Utils/TwingleShopUtils.php';
/**
* TwingleProduct BAO class.
* This class is used to implement the logic for the TwingleProduct entity.
*/
class CRM_Twingle_BAO_TwingleProduct extends CRM_Twingle_DAO_TwingleProduct {
/**
* Name of this product.
*/
public $name;
/**
* Is this product active?
*/
public $is_active;
/**
* Price of this product.
*/
public $price;
/**
* Sort order of this product.
*/
public $sort;
/**
* Short description of this Product.
*/
public $text;
/**
* Long description of this Product.
*/
public $description;
/**
* ID of the corresponding Twingle Shop.
*/
public $project_id;
/**
* ID of the financial type of this product.
*/
public $financial_type_id;
/**
* Timestamp of the last update in Twingle db.
*/
public $tw_updated_at;
/**
* The values of this attributes can be 0.
* (For filtering purposes)
*/
protected const CAN_BE_ZERO = [
"price",
"sort",
];
/**
* Attributes that need to be converted to int.
*/
protected const STR_TO_INT_CONVERSION = [
"id",
"twingle_shop_id",
"financial_type_id",
"price_field_id",
"project_id",
"external_id",
"tw_updated_at",
"tw_created_at",
"price",
"sort",
];
/**
* Attributes that need to be converted to boolean.
*/
protected const INT_TO_BOOL_CONVERSION = [
"is_active",
];
/**
* String to date conversion.
*/
protected const STR_TO_DATE_CONVERSION = [
"created_at",
"updated_at",
];
/**
* Empty string to null conversion.
*/
protected const EMPTY_STRING_TO_NULL = [
"price",
];
/**
* Allowed product attributes.
* Attributes that we currently don't support are commented out.
*/
protected const ALLOWED_ATTRIBUTES = [
"id" => CRM_Utils_Type::T_INT,
"external_id" => CRM_Utils_Type::T_INT,
"name" => CRM_Utils_Type::T_STRING,
"is_active" => CRM_Utils_Type::T_BOOLEAN,
"description" => CRM_Utils_Type::T_STRING,
"price" => CRM_Utils_Type::T_INT,
"created_at" => CRM_Utils_Type::T_INT,
"tw_created_at" => CRM_Utils_Type::T_INT,
"updated_at" => CRM_Utils_Type::T_INT,
"tw_updated_at" => CRM_Utils_Type::T_INT,
"is_orphaned" => CRM_Utils_Type::T_BOOLEAN,
"is_outdated" => CRM_Utils_Type::T_BOOLEAN,
"project_id" => CRM_Utils_Type::T_INT,
"sort" => CRM_Utils_Type::T_INT,
"financial_type_id" => CRM_Utils_Type::T_INT,
"twingle_shop_id" => CRM_Utils_Type::T_INT,
"price_field_id" => CRM_Utils_Type::T_INT,
# "text" => \CRM_Utils_Type::T_STRING,
# "images" => \CRM_Utils_Type::T_STRING,
# "categories" = \CRM_Utils_Type::T_STRING,
# "internal_id" => \CRM_Utils_Type::T_STRING,
# "has_zero_price" => \CRM_Utils_Type::T_BOOLEAN,
# "name_plural" => \CRM_Utils_Type::T_STRING,
# "max_count" => \CRM_Utils_Type::T_INT,
# "has_textinput" => \CRM_Utils_Type::T_BOOLEAN,
# "count" => \CRM_Utils_Type::T_INT,
];
/**
* Change attribute names to match the database column names.
*
* @param array $values
* Array with product data from Twingle API
*
* @return array
*/
public static function renameTwingleAttrs(array $values) {
$new_values = [];
foreach ($values as $key => $value) {
// replace 'id' with 'external_id'
if ($key == 'id') {
$key = 'external_id';
}
// replace 'updated_at' with 'tw_updated_at'
if ($key == 'updated_at') {
$key = 'tw_updated_at';
}
// replace 'created_at' with 'tw_created_at'
if ($key == 'created_at') {
$key = 'tw_created_at';
}
$new_values[$key] = $value;
}
return $new_values;
}
/**
* Load product data.
*
* @param array $product_data
* Array with product data
*
* @return void
*
* @throws ProductException
* @throws \Exception
*/
public function load(array $product_data): void {
// Filter for allowed attributes
filter_attributes(
$product_data,
self::ALLOWED_ATTRIBUTES,
self::CAN_BE_ZERO,
);
// Does this product allow to enter a custom price?
$custom_price = array_key_exists('price', $product_data) && $product_data['price'] === Null;
if (!$custom_price && isset($product_data['price_field_id'])) {
try {
$price_field = civicrm_api3('PriceField', 'getsingle', [
'id' => $product_data['price_field_id'],
'return' => 'is_enter_qty',
]);
$custom_price = (bool) $price_field['is_enter_qty'];
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts("Could not find PriceField for Twingle Product ['id': %1, 'external_id': %2]: %3",
[
1 => $product_data['id'],
2 => $product_data['external_id'],
3 => $e->getMessage(),
]),
ProductException::ERROR_CODE_PRICE_FIELD_NOT_FOUND);
}
}
// Amend data from corresponding PriceFieldValue
if (isset($product_data['price_field_id'])) {
try {
$price_field_value = civicrm_api3('PriceFieldValue', 'getsingle', [
'price_field_id' => $product_data['price_field_id'],
]);
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts("Could not find PriceFieldValue for Twingle Product ['id': %1, 'external_id': %2]: %3",
[
1 => $product_data['id'],
2 => $product_data['external_id'],
3 => $e->getMessage(),
]),
ProductException::ERROR_CODE_PRICE_FIELD_VALUE_NOT_FOUND);
}
$product_data['name'] = $product_data['name'] ?? $price_field_value['label'];
$product_data['price'] = $custom_price ? Null : $product_data['price'] ?? $price_field_value['amount'];
$product_data['financial_type_id'] = $product_data['financial_type_id'] ?? $price_field_value['financial_type_id'];
$product_data['is_active'] = $product_data['is_active'] ?? $price_field_value['is_active'];
$product_data['sort'] = $product_data['sort'] ?? $price_field_value['weight'];
$product_data['description'] = $product_data['description'] ?? $price_field_value['description'];
}
// Change data types
try {
convert_str_to_int($product_data, self::STR_TO_INT_CONVERSION);
convert_int_to_bool($product_data, self::INT_TO_BOOL_CONVERSION);
convert_str_to_date($product_data, self::STR_TO_DATE_CONVERSION);
convert_empty_string_to_null($product_data, self::EMPTY_STRING_TO_NULL);
}
catch (\Exception $e) {
throw new ProductException($e->getMessage(), ProductException::ERROR_CODE_ATTRIBUTE_WRONG_DATA_TYPE);
}
// Validate data types
try {
validate_data_types($product_data, self::ALLOWED_ATTRIBUTES);
}
catch (\Exception $e) {
throw new ProductException($e->getMessage(), ProductException::ERROR_CODE_ATTRIBUTE_WRONG_DATA_TYPE);
}
// Set attributes
foreach ($product_data as $key => $value) {
$this->$key = $value;
}
}
/**
* Creates a price field to represents this product in CiviCRM.
*
* @param string $mode
* 'create' or 'edit'
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
public function createPriceField() {
// Define mode for PriceField
$mode = $this->price_field_id ? 'edit' : 'create';
$action = $mode == 'create' ? 'create' : 'update';
// Check if PriceSet for this Shop already exists
try {
$price_field = civicrm_api3('PriceField', 'get', [
'name' => 'tw_product_' . $this->external_id,
]);
if ($price_field['count'] > 0 && $mode == 'create') {
throw new ProductException(
E::ts('PriceField for this Twingle Product already exists.'),
ProductException::ERROR_CODE_PRICE_FIELD_ALREADY_EXISTS,
);
} elseif ($price_field['count'] == 0 && $mode == 'edit') {
throw new ProductException(
E::ts('PriceField for this Twingle Product does not exist and cannot be edited.'),
ProductException::ERROR_CODE_PRICE_FIELD_NOT_FOUND,
);
}
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('Could not check if PriceField for this Twingle Product already exists.'),
ProductException::ERROR_CODE_PRICE_FIELD_NOT_FOUND,
);
}
// Try to find corresponding price set via TwingleShop
try {
$shop = civicrm_api3('TwingleShop', 'getsingle', [
'id' => $this->twingle_shop_id,
]);
$this->price_set_id = (int) $shop['price_set_id'];
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('Could not find PriceSet for this Twingle Product.'),
ProductException::ERROR_CODE_PRICE_SET_NOT_FOUND,
);
}
// Create PriceField
$price_field_data = [
'price_set_id' => $this->price_set_id,
'name' => 'tw_product_' . $this->external_id,
'label' => $this->name,
'is_active' => $this->is_active,
'weight' => $this->sort,
'html_type' => 'Text',
'is_required' => false,
];
// If the product has no fixed price, allow the user to enter a custom price
if ($this->price === Null) {
$price_field_data['is_enter_qty'] = true;
$price_field_data['is_display_amounts'] = false;
}
// Add id if in edit mode
if ($mode == 'edit') {
$price_field_data['id'] = $this->price_field_id;
}
try {
$price_field = civicrm_api4(
'PriceField',
$action,
['values' => $price_field_data],
)->first();
$this->price_field_id = (int) $price_field['id'];
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('Could not create PriceField for this Twingle Product: %1',
[1 => $e->getMessage()]),
ProductException::ERROR_CODE_COULD_NOT_CREATE_PRICE_FIELD);
}
// Try to find existing PriceFieldValue if in edit mode
$price_field_value = NULL;
if ($mode == 'edit') {
try {
$price_field_value = civicrm_api3('PriceFieldValue', 'getsingle', [
'price_field_id' => $this->price_field_id,
]);
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('Could not find PriceFieldValue for this Twingle Product: %1',
[1 => $e->getMessage()]),
ProductException::ERROR_CODE_PRICE_FIELD_VALUE_NOT_FOUND);
}
}
// 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 === Null ? 1 : $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 {
civicrm_api4(
'PriceFieldValue',
$action,
['values' => $price_field_value_data],
);
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('Could not create PriceFieldValue for this Twingle Product: %1',
[1 => $e->getMessage()]),
ProductException::ERROR_CODE_COULD_NOT_CREATE_PRICE_FIELD_VALUE);
}
}
/**
* Returns this TwingleProduct's attributes.
*
* @return array
* @throws \CRM_Core_Exception
*/
public function getAttributes() {
// Filter for allowed attributes
return array_intersect_key(
get_object_vars($this),
$this::ALLOWED_ATTRIBUTES
) // Add financial type id of this product if it exists
+ ['financial_type_id' => $this->getFinancialTypeId()];
}
/**
* Find TwingleProduct by its external ID.
*
* @param int $external_id
* External id of the product (by Twingle)
*
* @return CRM_Twingle_BAO_TwingleProduct|null
* TwingleProduct object or NULL if not found
*
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
* @throws \Civi\Core\Exception\DBQueryException
*/
public static function findByExternalId($external_id) {
$dao = CRM_Twingle_BAO_TwingleShop::executeQuery("SELECT * FROM civicrm_twingle_product WHERE external_id = %1",
[1 => [$external_id, 'String']]);
if ($dao->fetch()) {
$product = new self();
$product->load($dao->toArray());
return $product;
}
return NULL;
}
/**
* Add Twingle Product
*
* @param string $mode
* 'create' or 'edit'
* @return array
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
* @throws \Exception
*/
public function add($mode = 'create') {
$tx = new CRM_Core_Transaction();
// Define mode
$mode = $this->id ? 'edit' : 'create';
// Try to lookup object in database
try {
$dao = CRM_Twingle_BAO_TwingleShop::executeQuery("SELECT * FROM civicrm_twingle_product WHERE external_id = %1",
[1 => [$this->external_id, 'String']]);
if ($dao->fetch()) {
$this->copyValues(array_merge($dao->toArray(), $this->getAttributes()));
}
}
catch (\Civi\Core\Exception\DBQueryException $e) {
throw new ProductException(
E::ts('Could not find TwingleProduct in database: ' . $e->getMessage()),
ShopException::ERROR_CODE_COULD_NOT_FIND_SHOP_IN_DB);
}
// Register pre-hook
$twingle_product_values = $this->getAttributes();
try {
\CRM_Utils_Hook::pre($mode, 'TwingleProduct', $this->id, $twingle_product_values);
} catch (\Exception $e) {
$tx->rollback();
throw $e;
}
$this->load($twingle_product_values);
// 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);
// Convert created_at to date string
$this->created_at = \CRM_Utils_Time::date('Y-m-d H:i:s', $this->created_at);
// Save object to database
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
$twingle_product_values = $this->getAttributes();
try {
\CRM_Utils_Hook::post($mode, 'TwingleProduct', $this->id, $twingle_product_values);
}
catch (\Exception $e) {
$tx->rollback();
throw $e;
}
$this->load($twingle_product_values);
return $result->toArray();
}
/**
* Delete TwingleProduct along with associated PriceField and PriceFieldValue.
*
* @override \CRM_Twingle_DAO_TwingleProduct::delete
* @throws \CRM_Core_Exception
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
function delete($useWhere = FALSE) {
// Register post-hook
$twingle_product_values = $this->getAttributes();
\CRM_Utils_Hook::pre('delete', 'TwingleProduct', $this->id, $twingle_product_values);
$this->load($twingle_product_values);
// Delete TwingleProduct
parent::delete($useWhere);
// Register post-hook
\CRM_Utils_Hook::post('delete', 'TwingleProduct', $this->id, $instance);
// Free global arrays associated with this object
$this->free();
return true;
}
/**
* Complements the data with the data that was fetched from Twingle.
*
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
public function complementWithDataFromTwingle($product_from_twingle) {
// Complement with data from Twingle
$this->load([
'project_id' => $product_from_twingle['project_id'],
'tw_updated_at' => $product_from_twingle['updated_at'],
'tw_created_at' => $product_from_twingle['created_at'],
]);
}
/**
* Check if the product is outdated.
*
* @param $product_from_twingle
*
* @return void
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
public function checkOutdated($product_from_twingle) {
// Mark outdated products which have a newer timestamp in Twingle
if ($this->updated_at < intval($product_from_twingle['updated_at'])) {
// Overwrite the product with the data from Twingle
$this->load(self::renameTwingleAttrs($product_from_twingle));
$this->is_outdated = TRUE;
}
}
/**
* Compare two products
*
* @param CRM_Twingle_BAO_TwingleProduct $product_to_compare_with
* Product from database
*
* @return bool
*/
public function equals($product_to_compare_with) {
return
$this->name === $product_to_compare_with->name &&
$this->description === $product_to_compare_with->description &&
$this->text === $product_to_compare_with->text &&
$this->price === $product_to_compare_with->price &&
$this->external_id === $product_to_compare_with->external_id;
}
/**
* Returns the financial type id of this product.
*
* @return int|null
* @throws \CRM_Core_Exception
*/
public function getFinancialTypeId(): ?int {
if (!empty($this->price_field_id)) {
$price_set = PriceField::get()
->addSelect('financial_type_id')
->addWhere('id', '=', $this->price_field_id)
->execute()
->first();
return $price_set['financial_type_id'];
}
return NULL;
}
/**
* Returns the price field value id of this product.
*
* @return int|null
* @throws \CRM_Core_Exception
*/
public function getPriceFieldValueId() {
if (!empty($this->price_field_id)) {
$price_field_value = PriceFieldValue::get()
->addSelect('id')
->addWhere('price_field_id', '=', $this->price_field_id)
->execute()
->first();
return $price_field_value['id'];
}
return NULL;
}
/**
* Delete PriceField and PriceFieldValue of this TwingleProduct if they exist.
*
* @return void
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
public function deletePriceField(): void {
// Before we can delete the PriceField we need to delete the associated
// PriceFieldValue
try {
$result = civicrm_api3('PriceFieldValue', 'getsingle',
['price_field_id' => $this->price_field_id]);
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('An Error occurred while searching for the associated PriceFieldValue: ' . $e->getMessage()),
ProductException::ERROR_CODE_PRICE_FIELD_VALUE_NOT_FOUND);
}
try {
civicrm_api3('PriceFieldValue', 'delete', ['id' => $result['id']]);
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('Could not delete associated PriceFieldValue: ' . $e->getMessage()),
ProductException::ERROR_CODE_COULD_NOT_DELETE_PRICE_FIELD_VALUE);
}
// Try to delete PriceField
// If no PriceField is found, we assume that it has already been deleted
try {
civicrm_api3('PriceField', 'delete',
['id' => $this->price_field_id]);
}
catch (CRM_Core_Exception $e) {
// Check if PriceField yet exists
try {
$result = civicrm_api3('PriceField', 'get',
['id' => $this->price_field_id]);
// Throw exception if PriceField still exists
if ($result['count'] > 0) {
throw new ProductException(
E::ts('PriceField for this Twingle Product still exists.'),
ProductException::ERROR_CODE_PRICE_FIELD_STILL_EXISTS);
}
}
catch (CRM_Core_Exception $e) {
throw new ProductException(
E::ts('An Error occurred while searching for the associated PriceField: ' . $e->getMessage()),
ProductException::ERROR_CODE_PRICE_FIELD_NOT_FOUND);
}
throw new ProductException(
E::ts('Could not delete associated PriceField: ' . $e->getMessage()),
ProductException::ERROR_CODE_COULD_NOT_DELETE_PRICE_FIELD);
}
$this->price_field_id = NULL;
}
}

View file

@ -0,0 +1,473 @@
<?php
// phpcs:disable
use CRM_Twingle_ExtensionUtil as E;
use Civi\Twingle\Shop\ApiCall;
use Civi\Twingle\Shop\Exceptions\ShopException;
use Civi\Twingle\Shop\Exceptions\ProductException;
use function Civi\Twingle\Shop\Utils\filter_attributes;
use function Civi\Twingle\Shop\Utils\convert_str_to_int;
use function Civi\Twingle\Shop\Utils\validate_data_types;
// phpcs:enable
require_once E::path() . '/Civi/Twingle/Shop/Utils/TwingleShopUtils.php';
class CRM_Twingle_BAO_TwingleShop extends CRM_Twingle_DAO_TwingleShop {
public const ALLOWED_ATTRIBUTES = [
'id' => \CRM_Utils_Type::T_INT,
'project_identifier' => \CRM_Utils_Type::T_STRING,
'numerical_project_id' => \CRM_Utils_Type::T_INT,
'name' => \CRM_Utils_Type::T_STRING,
'price_set_id' => \CRM_Utils_Type::T_INT,
'financial_type_id' => \CRM_Utils_Type::T_INT,
];
public const STR_TO_INT_CONVERSION = [
'id',
'numerical_project_id',
'price_set_id',
'financial_type_id',
];
/**
* @var array $products
* Array of Twingle Shop products (Cache)
*/
public $products;
/**
* FK to Financial Type
*
* @var int
*/
public $financial_type_id;
/**
* TwingleShop constructor
*/
public function __construct() {
parent::__construct();
// Get TwingleApiCall singleton
$this->twingleApi = ApiCall::singleton();
}
/**
* Get Twingle Shop from database by its project identifier
* (like 'tw620214349ac97')
*
* @param string $project_identifier
* Twingle project identifier
*
* @return CRM_Twingle_BAO_TwingleShop
*
* @throws ShopException
* @throws \Civi\Twingle\Shop\Exceptions\ApiCallError
* @throws \CRM_Core_Exception
*/
public static function findByProjectIdentifier(string $project_identifier) {
$shop = new CRM_Twingle_BAO_TwingleShop();
$shop->get('project_identifier', $project_identifier);
if (!$shop->id) {
$shop->fetchDataFromTwingle($project_identifier);
}
else {
$shop->price_set_id = civicrm_api3('PriceSet', 'getvalue',
['return' => 'id', 'name' => $project_identifier]);
}
return $shop;
}
/**
* Load Twingle Shop data
*
* @param array $shop_data
* Array with shop data
*
* @return void
*
* @throws ShopException
*/
public function load(array $shop_data): void {
// Filter for allowed attributes
filter_attributes($shop_data, self::ALLOWED_ATTRIBUTES);
// Convert string to int
try {
convert_str_to_int($shop_data, self::STR_TO_INT_CONVERSION);
}
catch (Exception $e) {
throw new ShopException($e->getMessage(), ShopException::ERROR_CODE_ATTRIBUTE_WRONG_DATA_TYPE);
}
// Validate data types
try {
validate_data_types($shop_data, self::ALLOWED_ATTRIBUTES);
}
catch (Exception $e) {
throw new ShopException($e->getMessage(), ShopException::ERROR_CODE_ATTRIBUTE_WRONG_DATA_TYPE);
}
// Set attributes
foreach ($shop_data as $key => $value) {
$this->$key = $value;
}
}
/**
* Get attributes
*
* @return array
*/
function getAttributes(): array {
return [
'id' => $this->id,
'project_identifier' => $this->project_identifier,
'numerical_project_id' => $this->numerical_project_id,
'name' => $this->name,
'price_set_id' => $this->price_set_id,
'financial_type_id' => $this->financial_type_id,
];
}
/**
* Add Twingle Shop
*
* @param string $mode
* 'create' or 'edit'
* @return array
* @throws \Civi\Twingle\Shop\Exceptions\ShopException
*/
public function add($mode = 'create') {
// Try to lookup object in database
try {
$dao = self::executeQuery("SELECT * FROM civicrm_twingle_shop WHERE project_identifier = %1",
[1 => [$this->project_identifier, 'String']]);
if ($dao->fetch()) {
$this->load($dao->toArray());
}
} catch (\Civi\Core\Exception\DBQueryException $e) {
throw new ShopException(
E::ts('Could not find TwingleShop in database: ' . $e->getMessage()),
ShopException::ERROR_CODE_COULD_NOT_FIND_SHOP_IN_DB);
}
// Register pre-hook
$twingle_shop_values = $this->getAttributes();
\CRM_Utils_Hook::pre($mode, 'TwingleShop', $this->id, $twingle_shop_values);
$this->load($twingle_shop_values);
// Save object to database
$result = $this->save();
// Register post-hook
\CRM_Utils_Hook::post($mode, 'TwingleShop', $this->id, $instance);
return $result->toArray();
}
/**
* Delete object by deleting the associated PriceSet and letting the foreign
* key constraint do the rest.
*
* @throws \Civi\Twingle\Shop\Exceptions\ShopException*
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
function deleteByConstraint() {
// Register post-hook
$twingle_shop_values = $this->getAttributes();
\CRM_Utils_Hook::pre('delete', 'TwingleShop', $this->id, $twingle_shop_values);
$this->load($twingle_shop_values);
// Delete associated products
$this->deleteProducts();
// Try to get single PriceSet
try {
civicrm_api3('PriceSet', 'getsingle',
['id' => $this->price_set_id]);
}
catch (\CRM_Core_Exception $e) {
if ($e->getMessage() != 'Expected one PriceSet but found 0') {
throw new ShopException(
E::ts('Could not find associated PriceSet: ' . $e->getMessage()),
ShopException::ERROR_CODE_PRICE_SET_NOT_FOUND);
}
else {
// If no PriceSet is found, we can simply delete the TwingleShop
return $this->delete();
}
}
// Deleting the associated PriceSet will also lead to the deletion of this
// TwingleShop because of the foreign key constraint and cascading.
try {
$result = civicrm_api3('PriceSet', 'delete',
['id' => $this->price_set_id]);
} catch (\CRM_Core_Exception $e) {
throw new ShopException(
E::ts('Could not delete associated PriceSet: ' . $e->getMessage()),
ShopException::ERROR_CODE_COULD_NOT_DELETE_PRICE_SET);
}
// Register post-hook
\CRM_Utils_Hook::post('delete', 'TwingleShop', $this->id, $instance);
// Free global arrays associated with this object
$this->free();
return $result['is_error'] == 0;
}
/**
* Fetch Twingle Shop products from Twingle
*
* @return array
* array of CRM_Twingle_Shop_BAO_Product
*
* @throws \Civi\Twingle\Shop\Exceptions\ApiCallError;
* @throws \Civi\Twingle\Shop\Exceptions\ProductException;
* @throws \Civi\Core\Exception\DBQueryException
* @throws \CRM_Core_Exception
*/
public function fetchProducts(): array {
// Establish connection, if not already connected
if (!$this->twingleApi->isConnected) {
$this->twingleApi->connect();
}
// Fetch products from Twingle API
$products_from_twingle = $this->twingleApi->get(
'project',
$this->numerical_project_id,
'products',
);
// Fetch products from database
if ($this->id) {
$products_from_db = $this->getProducts();
$products_from_twingle = array_reduce($products_from_twingle, function($carry, $product) {
$carry[$product['id']] = $product;
return $carry;
}, []);
foreach ($products_from_db as $product) {
/* @var CRM_Twingle_BAO_TwingleProduct $product */
// Find orphaned products which are in the database but not in Twingle
$found = array_key_exists($product->external_id, $products_from_twingle);
if (!$found) {
$product->is_orphaned = TRUE;
}
else {
// Complement with data from Twingle
$product->complementWithDataFromTwingle($products_from_twingle[$product->external_id]);
// Mark outdated products which have a newer version in Twingle
$product->checkOutdated($products_from_twingle[$product->external_id]);
}
$this->products[] = $product;
}
}
// Create array with external_id as key
$products = array_reduce($this->products ?? [], function($carry, $product) {
$carry[$product->external_id] = $product;
return $carry;
}, []);
// Add new products from Twingle
foreach ($products_from_twingle as $product_from_twingle) {
$found = array_key_exists($product_from_twingle['id'], $products);
if (!$found) {
$product = new CRM_Twingle_BAO_TwingleProduct();
$product->load(CRM_Twingle_BAO_TwingleProduct::renameTwingleAttrs($product_from_twingle));
$product->twingle_shop_id = $this->id;
$this->products[] = $product;
}
}
return $this->products;
}
/**
* Get associated products.
*
* @return array[Civi\Twingle\Shop\BAO\TwingleProduct]
* @throws \Civi\Core\Exception\DBQueryException
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
public function getProducts() {
$products = [];
$result = CRM_Twingle_BAO_TwingleProduct::executeQuery(
"SELECT * FROM civicrm_twingle_product WHERE twingle_shop_id = %1",
[1 => [$this->id, 'Integer']]
);
while ($result->fetch()) {
$product = new CRM_Twingle_BAO_TwingleProduct();
$product->load($result->toArray());
$products[] = $product;
}
return $products;
}
/**
* 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') {
// Define mode
$mode = $this->price_set_id ? 'edit' : 'create';
// Check if PriceSet for this Shop already exists
try {
$price_set = civicrm_api3('PriceSet', 'get', [
'name' => $this->project_identifier,
]);
if ($price_set['count'] > 0 && $mode == 'create') {
throw new ShopException(
E::ts('PriceSet for this Twingle Shop already exists.'),
ShopException::ERROR_CODE_PRICE_SET_ALREADY_EXISTS,
);
}
elseif ($price_set['count'] == 0 && $mode == 'edit') {
throw new ShopException(
E::ts('PriceSet for this Twingle Shop does not exist and cannot be edited.'),
ShopException::ERROR_CODE_PRICE_SET_NOT_FOUND,
);
}
} catch (\CRM_Core_Exception $e) {
throw new ShopException(
E::ts('Could not check if PriceSet for this TwingleShop already exists.'),
ShopException::ERROR_CODE_PRICE_SET_NOT_FOUND,
);
}
// Create PriceSet
$price_set_data = [
'name' => $this->project_identifier,
'title' => "$this->name ($this->project_identifier)",
'is_active' => 1,
'extends' => 2,
'financial_type_id' => $this->financial_type_id,
];
// Set id if in edit mode
if ($mode == 'edit') {
$price_set_data['id'] = $this->price_set_id;
}
try {
$price_set = civicrm_api4('PriceSet', 'create',
['values' => $price_set_data])->first();
$this->price_set_id = (int) $price_set['id'];
} catch (\CRM_Core_Exception $e) {
throw new ShopException(
E::ts('Could not create PriceSet for this TwingleShop.'),
ShopException::ERROR_CODE_COULD_NOT_CREATE_PRICE_SET,
);
}
}
/**
* Retrieves the numerical project ID and the name of this shop from Twingle.
*
* @throws \Civi\Twingle\Shop\Exceptions\ShopException
* @throws \Civi\Twingle\Shop\Exceptions\ApiCallError
*/
private function fetchDataFromTwingle() {
// Establish connection, if not already connected
if (!$this->twingleApi->isConnected) {
$this->twingleApi->connect();
}
// Get shops from Twingle if not cached
$shops = \Civi::cache('long')->get('twingle_shops');
if (empty($shops)) {
$this::fetchShops($this->twingleApi);
$shops = \Civi::cache('long')->get('twingle_shops');
}
// Set Shop ID and name
foreach ($shops as $shop) {
if (isset($shop['identifier']) && $shop['identifier'] == $this->project_identifier) {
$this->numerical_project_id = $shop['id'];
$this->name = $shop['name'];
}
}
// Throw an Exception if this Twingle Project is not of type 'shop'
if (!isset($this->numerical_project_id)) {
throw new ShopException(
E::ts('This Twingle Project is not a shop.'),
ShopException::ERROR_CODE_NOT_A_SHOP,
);
}
}
/**
* Retrieves all Twingle projects of the type 'shop'.
*
* @throws \Civi\Twingle\Shop\Exceptions\ShopException
*/
static private function fetchShops(ApiCall $api): void {
$organisationId = $api->organisationId;
try {
$projects = $api->get(
'project',
NULL,
'by-organisation',
$organisationId,
);
$shops = array_filter(
$projects,
function($project) {
return isset($project['type']) && $project['type'] == 'shop';
}
);
\Civi::cache('long')->set('twingle_shops', $shops);
}
catch (Exception $e) {
throw new ShopException(
E::ts('Could not retrieve Twingle projects from API.
Please check your API credentials.'),
ShopException::ERROR_CODE_COULD_NOT_GET_PROJECTS,
);
}
}
/**
* Deletes all associated products.
*
* @return void
* @throws \Civi\Twingle\Shop\Exceptions\ProductException
*/
public function deleteProducts() {
try {
$products = $this->getProducts();
} catch (\Civi\Core\Exception\DBQueryException $e) {
throw new ProductException(
E::ts('Could not retrieve associated products: ' . $e->getMessage()),
ProductException::ERROR_CODE_COULD_NOT_GET_PRODUCTS
);
}
try {
foreach ($products as $product) {
$product->delete();
}
}
catch (ProductException $e) {
throw new ProductException(
E::ts('Could not delete associated products: ' . $e->getMessage()),
ProductException::ERROR_CODE_COULD_NOT_DELETE_PRICE_SET
);
}
}
}

View file

@ -0,0 +1,325 @@
<?php
/**
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
*
* Generated from de.systopia.twingle/xml/schema/CRM/Twingle/TwingleProduct.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
* (GenCodeChecksum:b8ced533ba6f4249619ffe5353965a4f)
*/
use CRM_Twingle_ExtensionUtil as E;
/**
* Database access object for the TwingleProduct entity.
*/
class CRM_Twingle_DAO_TwingleProduct extends CRM_Core_DAO {
const EXT = E::LONG_NAME;
const TABLE_ADDED = '';
/**
* Static instance to hold the table name.
*
* @var string
*/
public static $_tableName = 'civicrm_twingle_product';
/**
* Should CiviCRM log any modifications to this table in the civicrm_log table.
*
* @var bool
*/
public static $_log = FALSE;
/**
* Unique TwingleProduct ID
*
* @var int|string|null
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $id;
/**
* The ID of this product in the Twingle database
*
* @var int|string
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $external_id;
/**
* FK to Price Field
*
* @var int|string
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $price_field_id;
/**
* FK to Twingle Shop
*
* @var int|string|null
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $twingle_shop_id;
/**
* Timestamp of when the product was created in the database
*
* @var string
* (SQL type: datetime)
* Note that values will be retrieved from the database as a string.
*/
public $created_at;
/**
* Timestamp of when the product was last updated in the database
*
* @var string
* (SQL type: datetime)
* Note that values will be retrieved from the database as a string.
*/
public $updated_at;
/**
* Class constructor.
*/
public function __construct() {
$this->__table = 'civicrm_twingle_product';
parent::__construct();
}
/**
* Returns localized title of this entity.
*
* @param bool $plural
* Whether to return the plural version of the title.
*/
public static function getEntityTitle($plural = FALSE) {
return $plural ? E::ts('Twingle Products') : E::ts('Twingle Product');
}
/**
* Returns foreign keys and entity references.
*
* @return array
* [CRM_Core_Reference_Interface]
*/
public static function getReferenceColumns() {
if (!isset(\Civi::$statics[__CLASS__]['links'])) {
\Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__);
\Civi::$statics[__CLASS__]['links'][] = new \CRM_Core_Reference_Basic(self::getTableName(), 'price_field_id', 'civicrm_contact', 'id');
\Civi::$statics[__CLASS__]['links'][] = new \CRM_Core_Reference_Basic(self::getTableName(), 'twingle_shop_id', 'civicrm_twingle_shop', 'id');
\CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', \Civi::$statics[__CLASS__]['links']);
}
return \Civi::$statics[__CLASS__]['links'];
}
/**
* Returns all the column names of this table
*
* @return array
*/
public static function &fields() {
if (!isset(\Civi::$statics[__CLASS__]['fields'])) {
\Civi::$statics[__CLASS__]['fields'] = [
'id' => [
'name' => 'id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('ID'),
'description' => E::ts('Unique TwingleProduct ID'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_product.id',
'table_name' => 'civicrm_twingle_product',
'entity' => 'TwingleProduct',
'bao' => 'CRM_Twingle_DAO_TwingleProduct',
'localizable' => 0,
'html' => [
'type' => 'Number',
],
'readonly' => TRUE,
'add' => NULL,
],
'external_id' => [
'name' => 'external_id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('External ID'),
'description' => E::ts('The ID of this product in the Twingle database'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_product.external_id',
'table_name' => 'civicrm_twingle_product',
'entity' => 'TwingleProduct',
'bao' => 'CRM_Twingle_DAO_TwingleProduct',
'localizable' => 0,
'html' => [
'type' => 'Number',
],
'add' => NULL,
],
'price_field_id' => [
'name' => 'price_field_id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('Price Field ID'),
'description' => E::ts('FK to Price Field'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_product.price_field_id',
'table_name' => 'civicrm_twingle_product',
'entity' => 'TwingleProduct',
'bao' => 'CRM_Twingle_DAO_TwingleProduct',
'localizable' => 0,
'FKClassName' => 'CRM_Contact_DAO_Contact',
'add' => NULL,
],
'twingle_shop_id' => [
'name' => 'twingle_shop_id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('Twingle Shop ID'),
'description' => E::ts('FK to Twingle Shop'),
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_product.twingle_shop_id',
'table_name' => 'civicrm_twingle_product',
'entity' => 'TwingleProduct',
'bao' => 'CRM_Twingle_DAO_TwingleProduct',
'localizable' => 0,
'FKClassName' => 'CRM_Twingle_DAO_TwingleShop',
'add' => NULL,
],
'created_at' => [
'name' => 'created_at',
'type' => \CRM_Utils_Type::T_DATE + \CRM_Utils_Type::T_TIME,
'title' => E::ts('Created At'),
'description' => E::ts('Timestamp of when the product was created in the database'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_product.created_at',
'table_name' => 'civicrm_twingle_product',
'entity' => 'TwingleProduct',
'bao' => 'CRM_Twingle_DAO_TwingleProduct',
'localizable' => 0,
'add' => NULL,
],
'updated_at' => [
'name' => 'updated_at',
'type' => \CRM_Utils_Type::T_DATE + \CRM_Utils_Type::T_TIME,
'title' => E::ts('Updated At'),
'description' => E::ts('Timestamp of when the product was last updated in the database'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_product.updated_at',
'table_name' => 'civicrm_twingle_product',
'entity' => 'TwingleProduct',
'bao' => 'CRM_Twingle_DAO_TwingleProduct',
'localizable' => 0,
'add' => NULL,
],
];
\CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', \Civi::$statics[__CLASS__]['fields']);
}
return \Civi::$statics[__CLASS__]['fields'];
}
/**
* Return a mapping from field-name to the corresponding key (as used in fields()).
*
* @return array
* Array(string $name => string $uniqueName).
*/
public static function &fieldKeys() {
if (!isset(\Civi::$statics[__CLASS__]['fieldKeys'])) {
\Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(\CRM_Utils_Array::collect('name', self::fields()));
}
return \Civi::$statics[__CLASS__]['fieldKeys'];
}
/**
* Returns the names of this table
*
* @return string
*/
public static function getTableName() {
return self::$_tableName;
}
/**
* Returns if this table needs to be logged
*
* @return bool
*/
public function getLog() {
return self::$_log;
}
/**
* Returns the list of fields that can be imported
*
* @param bool $prefix
*
* @return array
*/
public static function &import($prefix = FALSE) {
$r = \CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'twingle_product', $prefix, []);
return $r;
}
/**
* Returns the list of fields that can be exported
*
* @param bool $prefix
*
* @return array
*/
public static function &export($prefix = FALSE) {
$r = \CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'twingle_product', $prefix, []);
return $r;
}
/**
* Returns the list of indices
*
* @param bool $localize
*
* @return array
*/
public static function indices($localize = TRUE) {
$indices = [];
return ($localize && !empty($indices)) ? \CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
}
}

View file

@ -0,0 +1,305 @@
<?php
/**
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
*
* Generated from de.systopia.twingle/xml/schema/CRM/Twingle/TwingleShop.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
* (GenCodeChecksum:95a46935c30b3da52e4df2bec871b962)
*/
use CRM_Twingle_ExtensionUtil as E;
/**
* Database access object for the TwingleShop entity.
*/
class CRM_Twingle_DAO_TwingleShop extends CRM_Core_DAO {
const EXT = E::LONG_NAME;
const TABLE_ADDED = '';
/**
* Static instance to hold the table name.
*
* @var string
*/
public static $_tableName = 'civicrm_twingle_shop';
/**
* Should CiviCRM log any modifications to this table in the civicrm_log table.
*
* @var bool
*/
public static $_log = FALSE;
/**
* Unique TwingleShop ID
*
* @var int|string|null
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $id;
/**
* Twingle Project Identifier
*
* @var string
* (SQL type: varchar(32))
* Note that values will be retrieved from the database as a string.
*/
public $project_identifier;
/**
* Numerical Twingle Project Identifier
*
* @var int|string
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $numerical_project_id;
/**
* FK to Price Set
*
* @var int|string|null
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
public $price_set_id;
/**
* name of the shop
*
* @var string
* (SQL type: varchar(64))
* Note that values will be retrieved from the database as a string.
*/
public $name;
/**
* Class constructor.
*/
public function __construct() {
$this->__table = 'civicrm_twingle_shop';
parent::__construct();
}
/**
* Returns localized title of this entity.
*
* @param bool $plural
* Whether to return the plural version of the title.
*/
public static function getEntityTitle($plural = FALSE) {
return $plural ? E::ts('Twingle Shops') : E::ts('Twingle Shop');
}
/**
* Returns foreign keys and entity references.
*
* @return array
* [CRM_Core_Reference_Interface]
*/
public static function getReferenceColumns() {
if (!isset(\Civi::$statics[__CLASS__]['links'])) {
\Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__);
\Civi::$statics[__CLASS__]['links'][] = new \CRM_Core_Reference_Basic(self::getTableName(), 'price_set_id', 'civicrm_price_set', 'id');
\CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', \Civi::$statics[__CLASS__]['links']);
}
return \Civi::$statics[__CLASS__]['links'];
}
/**
* Returns all the column names of this table
*
* @return array
*/
public static function &fields() {
if (!isset(\Civi::$statics[__CLASS__]['fields'])) {
\Civi::$statics[__CLASS__]['fields'] = [
'id' => [
'name' => 'id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('ID'),
'description' => E::ts('Unique TwingleShop ID'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_shop.id',
'table_name' => 'civicrm_twingle_shop',
'entity' => 'TwingleShop',
'bao' => 'CRM_Twingle_DAO_TwingleShop',
'localizable' => 0,
'html' => [
'type' => 'Number',
],
'readonly' => TRUE,
'add' => NULL,
],
'project_identifier' => [
'name' => 'project_identifier',
'type' => \CRM_Utils_Type::T_STRING,
'title' => E::ts('Project Identifier'),
'description' => E::ts('Twingle Project Identifier'),
'required' => TRUE,
'maxlength' => 32,
'size' => \CRM_Utils_Type::MEDIUM,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_shop.project_identifier',
'table_name' => 'civicrm_twingle_shop',
'entity' => 'TwingleShop',
'bao' => 'CRM_Twingle_DAO_TwingleShop',
'localizable' => 0,
'html' => [
'type' => 'Text',
],
'add' => NULL,
],
'numerical_project_id' => [
'name' => 'numerical_project_id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('Numerical Project ID'),
'description' => E::ts('Numerical Twingle Project Identifier'),
'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_shop.numerical_project_id',
'table_name' => 'civicrm_twingle_shop',
'entity' => 'TwingleShop',
'bao' => 'CRM_Twingle_DAO_TwingleShop',
'localizable' => 0,
'html' => [
'type' => 'Number',
],
'add' => NULL,
],
'price_set_id' => [
'name' => 'price_set_id',
'type' => \CRM_Utils_Type::T_INT,
'title' => E::ts('Price Set ID'),
'description' => E::ts('FK to Price Set'),
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_shop.price_set_id',
'table_name' => 'civicrm_twingle_shop',
'entity' => 'TwingleShop',
'bao' => 'CRM_Twingle_DAO_TwingleShop',
'localizable' => 0,
'FKClassName' => 'CRM_Price_DAO_PriceSet',
'add' => NULL,
],
'name' => [
'name' => 'name',
'type' => \CRM_Utils_Type::T_STRING,
'title' => E::ts('Name'),
'description' => E::ts('name of the shop'),
'required' => TRUE,
'maxlength' => 64,
'size' => \CRM_Utils_Type::BIG,
'usage' => [
'import' => FALSE,
'export' => FALSE,
'duplicate_matching' => FALSE,
'token' => FALSE,
],
'where' => 'civicrm_twingle_shop.name',
'table_name' => 'civicrm_twingle_shop',
'entity' => 'TwingleShop',
'bao' => 'CRM_Twingle_Shop_DAO_TwingleShop',
'localizable' => 0,
'html' => [
'type' => 'Text',
],
'add' => NULL,
],
];
\CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', \Civi::$statics[__CLASS__]['fields']);
}
return \Civi::$statics[__CLASS__]['fields'];
}
/**
* Return a mapping from field-name to the corresponding key (as used in fields()).
*
* @return array
* Array(string $name => string $uniqueName).
*/
public static function &fieldKeys() {
if (!isset(\Civi::$statics[__CLASS__]['fieldKeys'])) {
\Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(\CRM_Utils_Array::collect('name', self::fields()));
}
return \Civi::$statics[__CLASS__]['fieldKeys'];
}
/**
* Returns the names of this table
*
* @return string
*/
public static function getTableName() {
return self::$_tableName;
}
/**
* Returns if this table needs to be logged
*
* @return bool
*/
public function getLog() {
return self::$_log;
}
/**
* Returns the list of fields that can be imported
*
* @param bool $prefix
*
* @return array
*/
public static function &import($prefix = FALSE) {
$r = \CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'twingle_shop', $prefix, []);
return $r;
}
/**
* Returns the list of fields that can be exported
*
* @param bool $prefix
*
* @return array
*/
public static function &export($prefix = FALSE) {
$r = \CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'twingle_shop', $prefix, []);
return $r;
}
/**
* Returns the list of indices
*
* @param bool $localize
*
* @return array
*/
public static function indices($localize = TRUE) {
$indices = [];
return ($localize && !empty($indices)) ? \CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
}
}