Implement Phase 3: Multi-attribute search AND logic and Phase 4: Sort by attribute columns

Phase 3 - Multi-attribute Search:
- Add parse_attribute_search() method to parse search syntax like
  'color: blue size: large' or 'color:blue AND size:large'
- Update search_by_attributes() to support AND/OR logic for multiple
  attribute queries
- Add search_by_attribute_value() private method for single value search

Phase 4 - Sort by Attribute Columns:
- Add get_attribute_sort_definition_id() method to detect attribute
  column sorting
- Update Item::search() to join attribute tables when sorting by
  attribute columns
- Update tabular_helper to make attribute columns sortable
- Add sanitizeSortColumnAttribute() method in Items controller to
  validate attribute definition IDs as sort columns

Fixes #2722 - sorting by attribute columns now works
This commit is contained in:
Ollama
2026-03-16 18:27:56 +00:00
committed by jekkos
parent 362f2925a5
commit f2fffa2723
3 changed files with 161 additions and 4 deletions

View File

@@ -63,6 +63,33 @@ class Items extends Secure_Controller
$this->config = config(OSPOS::class)->settings;
}
/**
* Sanitize sort column allowing standard columns and attribute definition IDs
*
* @param string|null $field The requested sort field
* @param string $default The default sort field
* @param array $attribute_ids Allowed attribute definition IDs
* @return string The validated sort field
*/
private function sanitizeSortColumnAttribute(?string $field, string $default, array $attribute_ids): string
{
if ($field === null) {
return $default;
}
$allowed_columns = ['items.item_id', 'item_number', 'name', 'category', 'company_name', 'cost_price', 'unit_price', 'quantity'];
if (in_array($field, $allowed_columns)) {
return $field;
}
if (ctype_digit($field) && in_array((int) $field, $attribute_ids, true)) {
return $field;
}
return $default;
}
/**
* @return string
*/
@@ -105,7 +132,11 @@ class Items extends Secure_Controller
$search = $this->request->getGet('search', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$limit = $this->request->getGet('limit', FILTER_SANITIZE_NUMBER_INT);
$offset = $this->request->getGet('offset', FILTER_SANITIZE_NUMBER_INT);
$sort = $this->sanitizeSortColumn(item_headers(), $this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'item_id');
$definition_names = $this->attribute->get_definitions_by_flags(Attribute::SHOW_IN_ITEMS);
$attribute_column_ids = array_keys($definition_names);
$sort = $this->sanitizeSortColumnAttribute($this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'item_id', $attribute_column_ids);
$order = $this->request->getGet('order', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$this->item_lib->set_item_location($this->request->getGet('stock_location'));