diff --git a/app/Config/Constants.php b/app/Config/Constants.php index d792d7b28..bf48752d8 100644 --- a/app/Config/Constants.php +++ b/app/Config/Constants.php @@ -100,6 +100,7 @@ const CHECKBOX = 'CHECKBOX'; const NO_DEFINITION_ID = 0; const CATEGORY_DEFINITION_ID = -1; const DEFINITION_TYPES = [GROUP, DROPDOWN, DECIMAL, TEXT, DATE, CHECKBOX]; +const ATTRIBUTE_VALUE_TYPES = ['attribute_value', 'attribute_decimal', 'attribute_date']; /** * Item Related Constants. diff --git a/app/Controllers/Items.php b/app/Controllers/Items.php index 609dbf1bb..7650e4493 100644 --- a/app/Controllers/Items.php +++ b/app/Controllers/Items.php @@ -1200,9 +1200,8 @@ class Items extends Secure_Controller */ private function saveAttributeData(array $row, array $itemData, array $definitions): bool { + helper('attribute'); foreach ($definitions as $definition) { - $attribute_name = $definition['definition_name']; - $attribute_value = $row["attribute_$attribute_name"]; $attributeName = $definition['definition_name']; $attributeValue = $row["attribute_$attributeName"]; @@ -1245,10 +1244,6 @@ class Items extends Secure_Controller $this->attribute->deleteAttributeLinks($itemId, $attributeData['definition_id']); - if (!$attribute_id) { - $attribute_id = $this->attribute->saveAttributeValue($value, $attribute_data['definition_id'], $item_id, false, $attribute_data['definition_type']); - } elseif (!$this->attribute->saveAttributeLink($item_id, $attribute_data['definition_id'], $attribute_id)) { - return false; if (!$attributeId) { $attributeId = $this->attribute->saveAttributeValue($value, $attributeData['definition_id'], $itemId, false, $attributeData['definition_type']); } else { @@ -1378,16 +1373,15 @@ class Items extends Secure_Controller switch ($definitionType) { case DROPDOWN: $attributeId = $attributeValue; + $this->attribute->saveAttributeLink($itemId, $definitionId, $attributeId); break; case DECIMAL: $attributeValue = parse_decimals($attributeValue); - // Fall through to save the attribute value + // no break default: $attributeId = $this->attribute->saveAttributeValue($attributeValue, $definitionId, $itemId, $attributeIds[$definitionId], $definitionType); break; } - - $this->attribute->saveAttributeLink($itemId, $definitionId, $attributeId); } } } diff --git a/app/Helpers/attribute_helper.php b/app/Helpers/attribute_helper.php new file mode 100644 index 000000000..1d6712369 --- /dev/null +++ b/app/Helpers/attribute_helper.php @@ -0,0 +1,33 @@ + 'attribute_date', + DECIMAL => 'attribute_decimal', + ]; + + return $columnMap[$input] ?? 'attribute_value'; +} + +/** + * Validates that the provided data type is an allowed attribute value type. + * + * @param string $dataType + * @return void + */ +function validateAttributeValueType(string $dataType): void +{ + if (!in_array($dataType, ATTRIBUTE_VALUE_TYPES, true)) { + throw new InvalidArgumentException('Invalid data type'); + } +} diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 7e9030544..a06e6acbb 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -708,6 +708,31 @@ class Attribute extends Model return $this->getEmptyObject('attribute_values'); } + /** + * Gets a single attribute value by attribute ID. + * + * @param int $attributeId The attribute ID to look up + * @param string $dataType The column name to retrieve (attribute_value, attribute_date, or attribute_decimal) + * @return string|float|null The attribute value. Note: MySQL returns values as follows: + * - attribute_value (TEXT): string + * - attribute_date (DATE): string in 'Y-m-d' format + * - attribute_decimal (DECIMAL): string or float depending on CodeIgniter configuration + * Returns null if the attribute_id is not found. + */ + public function getAttributeValueByAttributeId(int $attributeId, string $dataType): string|float|null + { + helper('attribute'); + validateAttributeValueType($dataType); + + $builder = $this->db->table('attribute_values'); + $builder->select($dataType); + $builder->where('attribute_id', $attributeId); + $builder->limit(1); + $row = $builder->get()->getRow(); + + return $row ? $row->$dataType : null; + } + /** * Initializes an empty object based on database definitions * @param string $table_name @@ -816,20 +841,10 @@ class Attribute extends Model $existingAttributeId = $this->attributeValueExists($attributeValue, $definitionType); - // New Attribute - if (empty($attribute_id) || empty($item_id) || $attribute_id == -1) { - $attribute_id = $this->attributeValueExists($attribute_value, $definition_type); // Update if ($existingAttributeId) { - - if (!$attribute_id) { - - $builder = $this->db->table('attribute_values'); - $builder->set(["attribute_$data_type" => $attribute_value]); - $builder->insert(); - - $attribute_id = $this->db->insertID(); - } + $attributeId = $existingAttributeId; + $storedValue = $this->getAttributeValueByAttributeId($attributeId, $dataType); if ($dataType === 'attribute_value' && is_string($storedValue)