This commit is contained in:
2024-01-29 10:39:53 +07:00
parent 545c404fdf
commit 72170f373a
143 changed files with 20188 additions and 3 deletions

View File

@@ -0,0 +1,320 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\System\Url;
use Hura8\Components\Brand\Model\BrandModel;
class ProductFilterBuilderController {
protected $_request_url = '';
protected $_url_elements = [
'scheme' => '',
'host' => '',
'port' => '',
'user' => '',
'pass' => '',
'path' => '',
'query' => [],
'fragment' => '',
];
protected $_price_format = '';
protected $_brand_format = '';
protected $_filter_format = '';
public function __construct($request_url) {
if(defined('PRICE_FILTER_FORMAT') && PRICE_FILTER_FORMAT) {
$this->_price_format = PRICE_FILTER_FORMAT;
}
if(defined('BRAND_FILTER_FORMAT') && BRAND_FILTER_FORMAT) {
$this->_brand_format = BRAND_FILTER_FORMAT;
}
if(defined('ATTRIBUTE_FILTER_FORMAT') && ATTRIBUTE_FILTER_FORMAT ) {
$this->_filter_format = ATTRIBUTE_FILTER_FORMAT;
}
$this->_request_url = $request_url;
$this->_url_elements = Url::parse($request_url);
}
public function buildProductFilterFromUrl(array $existing_filters = []) {
$filters = [
"price" => $this->getPriceFilterRange(),
"brand" => $this->getBrandFilter(), // array(1,2,3,)
"collection" => $this->getGenericFilter('collection'), // array(1,2,3,)
"supplier" => $this->getGenericFilter('supplier'), // array(1,2,3,)
"rating" => $this->getGenericFilter('rating'), // array(1,2,3,)
"category" => $this->getGenericFilter('category'), // array(1,2,3,)
"status" => array(), // array(1,2,3,)
"query" => (isset($this->_url_elements['query']['q'])) ? $this->_url_elements['query']['q'] : '', // string search keyword
"hotType" => $this->getGenericFilter('hotType', 'string'),// array(saleoff | not | new)
"attribute" => $this->getAttributeFilter(), // array(1,2,3,)
"ids" => $this->getGenericFilter('ids'), // array(1,2,3,)
"promotion" => "",
"storeId" => $this->getGenericFilter('store'), // array(1,2,3,)
"other_filter" => $this->getGenericFilter('other_filter', 'string'), // array(in-stock, has-promotion etc...)
"spec_group_id" => $this->getGenericFilter('spec_group_id'),
];
// debug_var(array_merge($filters, $existing_filters));
if(sizeof($existing_filters)) {
foreach ($existing_filters as $key => $values) {
if(!isset($filters[$key])) continue;
if(!$values) continue;
if(is_array($values) && is_array($filters[$key])) {
$filters[$key] = array_merge($filters[$key], $values);
}else{
$filters[$key] = $values;
}
}
}
return $filters ;
}
protected function getGenericFilter($url_para, $data_type='int') {
$value = (isset($this->_url_elements['query'][$url_para])) ? $this->_url_elements['query'][$url_para] : '';
if($data_type == 'int') {
$safe_value = trim(preg_replace("/[^0-9_\-\,]/i", '', $value));
}else{
$safe_value = trim(preg_replace("/[^a-z0-9_\-\.\,]/i", '', $value));
}
if(!$safe_value) return [];
$safe_value_list = explode(FILTER_VALUE_SEPARATOR, $safe_value);
return array_values(array_filter($safe_value_list));
}
protected function getBrandFilter()
{
if($this->_brand_format == 'brand_index'){
$objBrandModel = new BrandModel();
$result = [];
$brand_filters = $this->getGenericFilter('brand', 'string');
foreach ($brand_filters as $_brand) {
if(is_int($_brand)) {
$result[] = $_brand;
}
$brand_info = $objBrandModel->getInfoByUrl( $_brand);
if(!$brand_info) continue;
$result[] = $brand_info['id'];
}
return $result;
}
// default
return $this->getGenericFilter('brand');
}
protected function getAttributeFilter(array $category_list_id = []) {
if($this->_filter_format == 'filter_code') {
$excluded_keys = [
'q',
'p',
'min', 'max',
'brand',
'page',
'request_path',
'category',
'supplier', 'collection',
'ids',
'filter',' hotType',
'other_filter',
'rating', 'price',
// special ajax key
'action','action_type', '_auto'
];
$attr_filter_params = [];
foreach ( $this->_url_elements['query'] as $key => $value) {
if(in_array($key, $excluded_keys) || !$value) continue;
$attr_filter_params[$key] = explode(',', urldecode(urldecode($value)));
}
if(sizeof($attr_filter_params)) {
$category_attributes = $this->getAttributesForCategory($category_list_id);
//debug_var($category_attributes);
$match_attr_value_ids = [];
foreach ($attr_filter_params as $attr_filter_code => $attr_value_api_key_list) {
foreach ($category_attributes as $attribute) {
if($attribute['filter_code'] != $attr_filter_code) continue;
foreach ($attribute['value_list'] as $_index => $_value_info) {
foreach ($attr_value_api_key_list as $attr_value_api_key) {
if($_value_info['api_key'] == $attr_value_api_key) {
$match_attr_value_ids[] = $_value_info['id'];
}
}
}
}
}
return $match_attr_value_ids;
}
}
// default
return $this->getGenericFilter('filter');
}
protected function getAttributesForCategory(array $category_ids){
$category_att_id_list = array();
$attr_query_cond = (sizeof($category_ids)) ? " AND category_id IN (".join(',', $category_ids).") " : "";
$query = $this->db->runQuery(" SELECT `attr_id` FROM `idv_attribute_category` WHERE 1 ". $attr_query_cond);
foreach ($this->db->fetchAll($query) as $rs ){
$category_att_id_list[] = $rs['attr_id'];
}
if(!sizeof($category_att_id_list)) return array();
$query = $this->db->query("
SELECT
attval.id ,
attval.attributeId ,
attval.value ,
attval.api_key ,
att.attribute_code ,
att.filter_code
FROM ".TB_ATTRIBUTE_VALUE." attval
LEFT JOIN ".TB_ATTRIBUTE." att ON attval.attributeId = att.id
WHERE att.id IN (".join(',', $category_att_id_list).") AND att.isSearch=1
ORDER BY attval.ordering DESC ");
$attribute_list = [];
foreach ($this->db->fetchAll($query) as $rs ){
$att_value_id = $rs['id'];
$att_id = $rs['attributeId'];
$value_info = array(
"id" => $att_value_id,
"api_key" => $rs['api_key'],
);
if(!array_key_exists($att_id, $attribute_list)) {
$attribute_list[$att_id] = [
"id" => $att_id,
"code" => $rs['attribute_code'],
"filter_code" => $rs['filter_code'],
'value_list' => [$value_info],
];
}else{
$attribute_list[$att_id]['value_list'][] = $value_info;
}
}
return array_values($attribute_list);
}
// accept url format:
// default: ?min=1000&max=20000
// custom: ?p=15trieu-20-trieu
protected function getPriceFilterRange(){
// default format
if($this->_price_format != 'p') {
return array(
"min" => isset($this->_url_elements['query']['min']) ? intval($this->_url_elements['query']['min']) : 0 ,
"max" => isset($this->_url_elements['query']['max']) ? intval($this->_url_elements['query']['max']) : 0 ,
);
}
// custom price range query
$price_range_format = (isset($this->_url_elements['query']['p'])) ? $this->_url_elements['query']['p'] : ''; // duoi-10trieu , 10ngan-2trieu, 3trieu-6trieu, tren-30trieu
if(strpos($price_range_format, '-') === false) {
return array(
"min" => 0,
"max" => 0,
);
}
$unit_translation = [
'ngan' => 1000,
'trieu' => 1000000,
'ty' => 1000000000,
];
// duoi-10trieu, duoi-10ngan
if(strpos($price_range_format, 'duoi-') !== false) {
$unit_match = $this->findPriceUnitMatch(str_replace("duoi-", "", $price_range_format));
return array(
"min" => 0,
"max" => $unit_match['number'] * $unit_translation[$unit_match['unit']],
);
}
// tren-10trieu, tren-10ngan
if(strpos($price_range_format, 'tren-') !== false) {
$unit_match = $this->findPriceUnitMatch(str_replace("tren-", "", $price_range_format));
return array(
"min" => $unit_match['number'] * $unit_translation[$unit_match['unit']],
"max" => 0,
);
}
// 10ngan-2trieu, 3trieu-6trieu
$parts = explode('-', $price_range_format);
$min_part = $parts[0];
$max_part = $parts[1];
$min_match = $this->findPriceUnitMatch($min_part);
$max_match = $this->findPriceUnitMatch($max_part);
return [
"min" => $min_match['number'] * $unit_translation[$min_match['unit']],
"max" => $max_match['number'] * $unit_translation[$max_match['unit']],
];
}
protected function findPriceUnitMatch($str){
$match = [];
$pattern = "/^([\d]+)(ngan|trieu|ty)/i";
if(preg_match($pattern, $str, $match)){
return [
"number" => $match[1],
"unit" => $match[2],
];
}
return [
"number" => 0,
"unit" => 'trieu',
];
}
}

View File

@@ -0,0 +1,797 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\Components\Product\Model\ProductCollectionModel;
use Hura8\System\Url;
use Hura8\Components\Brand\Model\BrandModel;
use Hura8\Components\Product\AdminController\AProductHotController;
use Hura8\Components\Product\Model\ProductAttributeModel;
use Hura8\Components\Product\Model\ProductAttributeValueModel;
use Hura8\Components\Product\Model\ProductCategoryModel;
use Hura8\Components\Product\Model\ProductFilterModel;
use Hura8\Components\Product\Model\ProductSearchModel;
use Hura8\Interfaces\TableName;
use Hura8\Traits\ClassCacheTrait;
class ProductFilterController
{
use ClassCacheTrait;
protected $_request_url = '';
/* @var ProductFilterModel $objProductFilterModel */
protected $objProductFilterModel;
/*
all types of filtering representation must be finally translated to this format
For example:
- ?brand=sony => translated to brand=>array(2,),
- ?monitor_size=12inch&color=red => translated to attribute=> array(123, 23121,)
*/
protected $filters = [
"price" => array('max' => 0, 'min'=> 0),
"brand" => array(), // array(1,2,3,)
"collection" => array(), // array(1,2,3,)
"supplier" => array(), // array(1,2,3,)
"rating" => array(), // array(1,2,3,)
"category" => array(), // array(1,2,3,)
"status" => array(), // array(1,2,3,)
"query" => "", // string search keyword
"hotType" => array(),// array(saleoff | not | new)
"attribute" => array(), // array(1,2,3,)
"ids" => array(), // array(1,2,3,)
"excluded_ids" => array(), // array(1,2,3,)
"promotion" => "",
"storeId" => array(), // array(1,2,3,)
"other_filter" => array(), // array(in-stock, has-promotion etc...)
"spec_group_id" => array(), // array(1,2,3,)
];
public function __construct($request_url = '') {
$this->_request_url = $request_url;
}
public function getResult(
$current_page_id =1,
$number_per_page=10,
$sort_by = 'new',
array $existing_filters=[],
$current_category_ids = [],
$price_range = []
) {
$objProductFilterBuilder = new ProductFilterBuilderController($this->_request_url);
$built_filters = $objProductFilterBuilder->buildProductFilterFromUrl($existing_filters);
$this->setFilters($built_filters);
$product_result = $this->findProductListIdMatchFilters($current_page_id, $number_per_page, $sort_by);
//debug_var($product_result);
$objProductFilterOptions = new ProductFilterOptionsController(
$this->getFilters(),
$current_category_ids,
$product_result['item_list'],
$price_range
);
$objProductFilterOptionsTranslation = new ProductFilterOptionsTranslationController($this->_request_url);
list ( $filter_options, $filter_messages ) = $objProductFilterOptionsTranslation->getAllFilterOptions(
$objProductFilterOptions->categoryList(),
$objProductFilterOptions->attributeList(),
$objProductFilterOptions->brandList(),
$objProductFilterOptions->priceList()
);
return [
'total' => $product_result['total'],
'paged_product_list' => $product_result['item_list'],
'filter_options' => $filter_options,
'filter_messages' => $filter_messages,
];
}
public function getFilters() {
return $this->filters;
}
// allow to update filters
public function setFilters(array $new_filters) {
foreach ($new_filters as $key => $value) {
if(isset($this->filters[$key])) {
$this->filters[$key] = $value;
}
}
}
protected function createFilterCacheKey($sort_by) {
return md5(\json_encode($this->filters) . $sort_by);
}
// find a list of products that match filtering conditions
protected function findProductListIdMatchFilters($current_page_id, $number_per_page, $sort_by = "new" ) {
$cache_key = $this->createFilterCacheKey($sort_by);
return self::getCache($cache_key, function () use ($current_page_id, $number_per_page, $sort_by) {
return $this->findProductListIdMatchFilters_raw($current_page_id, $number_per_page, $sort_by );
});
}
protected function findProductListIdMatchFilters_raw($current_page_id=1, $number_per_page=10, $sort_by = "new" ) {
list( , , , $where_query ) = $this->buildSQLConditionFromFilters($sort_by);
$ordering_clause = $this->getOrderingClause($sort_by);
$objProductFilterModel = new ProductFilterModel();
list($total_number, $item_list) = $objProductFilterModel->findProductListIdMatchFilters([
$where_query,
$current_page_id,
$number_per_page,
$ordering_clause
]);
$final_result = [
"total" => $total_number,
"item_list" => $item_list,
];
return $final_result;
}
protected function buildSQLConditionFromFilters( $sort_by = "new" ) {
//list of available filters
$filterPath = [];
$filter_messages = [];
$where_query = [];
// system controls
if( ENABLE_PRODUCT_EXPIRE ) {
$where_query[] = " AND (from_time =0 OR from_time < '".CURRENT_TIME."')
AND (to_time > '".CURRENT_TIME."' OR to_time=0 ) ";
}
//other filters
if( array_key_exists("other_filter", $this->filters) && sizeof($this->filters["other_filter"])) {
foreach ($this->filters["other_filter"] as $_filter) {
switch ($_filter) {
case "in-stock";
$filter_messages[] = [
'title' => 'Còn hàng',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND quantity > 0 ";
break;
case "has-vat";
$filter_messages[] = [
'title' => 'Có thuế VAT',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `has_vat` = 1 ";
break;
case "out-stock";
$filter_messages[] = [
'title' => 'Hết hàng',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `quantity` = 0 ";
break;
case "has-market-price";
$filter_messages[] = [
'title' => 'Có giá thị trường',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND market_price > 0 ";
break;
case "no-price";
$filter_messages[] = [
'title' => 'Không có giá',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `price` = 0 ";
break;
case "no-warranty";
$filter_messages[] = [
'title' => 'Không có bảo hành',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND LENGTH(warranty) < 2 ";
break;
case "no-sku";
$filter_messages[] = [
'title' => 'Không mã kho hàng',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND LENGTH(sku) < 2 ";
break;
case "has-config";
$filter_messages[] = [
'title' => 'Không có cấu hình',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `config_count` > 0 ";
break;
case "no-image";
$filter_messages[] = [
'title' => 'Không có ảnh',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND image_count = 0 ";
break;
case "no-category";
$filter_messages[] = [
'title' => 'Không có danh mục',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `category` = '0' ";
break;
case "display-off";
$filter_messages[] = [
'title' => 'Đang ẩn',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `status`=0 ";
break;
case "display-on";
$filter_messages[] = [
'title' => 'Đang hiển thị',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND `status`=1 ";
break;
case "has-promotion":
$filter_messages[] = [
'title' => 'Có khuyến mại',
'reset' => Url::buildUrl($this->_request_url, ['other_filter' => '']),
];
$where_query[] = " AND LENGTH(`special_offer`) < 5 ";
break;
//...add more
}
}
}
/*// limit by admin permission
//1-1-2014 gioi han theo san pham danh muc ma quan tri nay quan ly
global $admin_permission;
$restricted_category_per_admin = (isset($admin_permission['permit'])) ? $admin_permission['permit']['product:category']['ids'] : [];
if(sizeof($restricted_category_per_admin)) {
$cat_query = $this->db->runQuery("
SELECT DISTINCT pro_id
FROM ".TB_PRODUCT_CATEGORY."
WHERE `category_id` IN (".join(",", $restricted_category_per_admin).")
LIMIT 5000
");
//lay danh sach danh muc cua san pham
$product_in_category = [];
foreach( $this->db->fetchAll($cat_query) as $cat_info ){
$product_in_category[] = $cat_info["pro_id"];
}
$where_query[] = (sizeof($product_in_category)) ? " AND id IN (". join(',', $product_in_category) .") " : " AND id = 0 ";
}*/
//- brand id or ids or brand_indexes
if( array_key_exists("brand", $this->filters) && sizeof($this->filters["brand"])) {
$objBrandModel = new BrandModel();
$condition = array();
foreach ($this->filters["brand"] as $brand_id) {
if(!$brand_id) continue;
$brand_info = $objBrandModel->getInfo( $brand_id);
if(!$brand_info) continue;
$filterPath["brand"][] = array(
"id" => $brand_info['id'],
"name" => $brand_info["title"],
);
$condition[] = " brandId = '".intval($brand_info['id'])."' ";
$filter_messages[] = [
'title' => $brand_info['title'],
'reset' => Url::buildUrl($this->_request_url, ['brand' => join(FILTER_VALUE_SEPARATOR, remove_item_from_array($this->filters["brand"], $brand_id ))] ),
];
}
if(sizeof($condition)) {
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
}
}
//- collection id or ids
if( array_key_exists("collection", $this->filters) && sizeof($this->filters["collection"])) {
$condition = array();
$objProductCollectionModel = new ProductCollectionModel();
foreach ($this->filters["collection"] as $_id) {
$collection_info = $objProductCollectionModel->getInfo($_id);
if(!$collection_info) continue;
$filterPath["collection"][] = array(
"id" => $_id,
"name" => $collection_info["title"],
);
$condition[] = " `id` IN ( SELECT product_id FROM ".TableName::PRODUCT_PER_COLLECTION." WHERE `collection_id`='".intval($collection_info['id'])."' ) ";
$filter_messages[] = [
'title' => 'Bộ sưu tập ',
'reset' => Url::buildUrl($this->_request_url, ['collection' => join(',', remove_item_from_array($this->filters["collection"], $_id))] ),
];
}
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
}
//- supplier id
if( array_key_exists("supplier", $this->filters) && sizeof($this->filters["supplier"])) {
/*$condition = array();
if(!$this->objSupplier) $this->objSupplier = new Supplier();
foreach ($this->filters["supplier"] as $_id) {
$_id = intval($_id);
$supplier_info = $this->objSupplier->getInfo($_id);
$filterPath["supplier"][] = array(
"id" => $_id,
"name" => $supplier_info["name"],
);
$condition[] = " supplier_id = '".$_id."' ";
$filter_messages[] = [
'title' => $supplier_info["name"],
'reset' => Url::buildUrl($this->_request_url, ['supplier' => join(',', remove_item_from_array($this->filters["supplier"], $_id))] ),
];
}
$where_query[] = " AND ( ".join(" OR ", $condition)." )";*/
}
//- rating: 1-> 5
if( array_key_exists("rating", $this->filters) && sizeof($this->filters["rating"])) {
$condition = array();
foreach ($this->filters["rating"] as $_id) {
$condition[] = " `rating` = '".intval($_id)."' ";
$filterPath["rating"][] = array(
"id" => $_id,
"name" => $_id,
);
$filter_messages[] = [
'title' => 'Đánh giá '.$_id,
'reset' => Url::buildUrl($this->_request_url, ['rating' => join(',', remove_item_from_array($this->filters["rating"], $_id))] ),
];
}
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
}
//- category id or ids
if( array_key_exists("category", $this->filters) && sizeof($this->filters["category"])) {
$objProductCategoryModel = new ProductCategoryModel();
$condition = array();
foreach ($this->filters["category"] as $cat_id) {
$cat_info = $objProductCategoryModel->getInfo($cat_id);
if(!$cat_info) continue;
if($cat_info["is_parent"]) {
$childListId = ($cat_info["child_ids"]) ?: '0';
$condition[] = " `category_id` IN (".$childListId .") ";
}else{
$condition[] = " `category_id` = '".$cat_id."' ";
}
$filterPath["category"][] = array(
"id" => $cat_id,
"name" => $cat_info['title'],
);
$filter_messages[] = [
'title' => $cat_info['title'],
'reset' => Url::buildUrl($this->_request_url, ['category' => join(FILTER_VALUE_SEPARATOR, remove_item_from_array($this->filters["category"], $cat_id))] ),
];
}
if(sizeof($condition)) {
$where_query[] = " AND `id` IN ( SELECT DISTINCT `item_id` FROM ".TableName::PRODUCT_PER_CATEGORY." WHERE " . join(" OR ", $condition) . " )";
}
}
//- status: 0|1|null
if( array_key_exists("status", $this->filters) && sizeof($this->filters["status"])) {
$where_query[] = " AND `status` IN (".join(',', $this->filters["status"]).") ";
}
// spec_group_id
if( array_key_exists("spec_group_id", $this->filters) && sizeof($this->filters["spec_group_id"])) {
$where_query[] = " AND `spec_group_id` IN (".join(',', $this->filters["spec_group_id"]).") ";
}
// detail_page_only: 0 | 1
if( array_key_exists("detail_page_only", $this->filters) && $this->filters["detail_page_only"]) {
$where_query[] = " AND `detail_page_only` = '".intval($this->filters['detail_page_only'])."' ";
}
//- query: search keyword
if( array_key_exists("query", $this->filters) && $this->filters["query"]) {
$keyword_search = $this->filters["query"];
$search_by_product_id = intval(preg_replace('/[^0-9]/i', '', $keyword_search));
// todo: add more
$filter_search = [];
if(isset($this->filters["brand"]) && $this->filters["brand"]) {
$filter_search['brand'] = ["IN", $this->filters["brand"]];
}
if(isset($this->filters["status"]) && $this->filters["status"]) {
$filter_search['status'] = ["IN", $this->filters["status"]];
}
$objProductSearchModel = new ProductSearchModel();
$match_result = $objProductSearchModel->find($keyword_search, $filter_search);
//debug_var($match_result);
$filterPath["search"] = array(
"id" => $keyword_search,
"name" => $keyword_search,
);
$filter_messages[] = [
'title' => $keyword_search,
'reset' => Url::buildUrl($this->_request_url, ['q' => ''] ),
];
if($search_by_product_id > 0) {
$where_query[] = (sizeof($match_result) > 0) ? " AND ( `id` IN (".join(',', $match_result).") OR `id` = '".$search_by_product_id."' ) " : " AND `id` = '".$search_by_product_id."' ";
}else{
$where_query[] = (sizeof($match_result) > 0) ? " AND `id` IN (".join(',', $match_result).") " : " AND `id` = -1 ";
}
}
//- hotType: saleoff | not | new | or combination of types
if( array_key_exists("hotType", $this->filters) && sizeof($this->filters["hotType"])) {
$config_hottype = AProductHotController::getProductHotTypeList();
$condition = array();
foreach ($this->filters["hotType"] as $_id) {
if(!array_key_exists($_id, $config_hottype)) continue;
$condition[] = " `hot_type` = '".$_id."' ";
$filter_messages[] = [
'title' => $config_hottype[$_id],
'reset' => Url::buildUrl($this->_request_url, ['hotType' => '']),
];
}
if(sizeof($condition)) {
$where_query[] = " AND `id` IN (SELECT pro_id FROM ".TB_PRODUCT_HOT." WHERE 1 AND ( ".join(" OR ", $condition)." ) ) ";
}
}
//- attribute values
/*
if( array_key_exists("attribute", $this->filters) && sizeof($this->filters["attribute"])) {
$filter_attr_value_list = $this->filters["attribute"];
//filter = attr_value_1-attr_value_2-attr_value_3,
$query_attr_id = [];
$count_filter = 0;
foreach($filter_attr_value_list as $attr_id){
$attr_id = (int) $attr_id;
if($attr_id) {
$query_attr_id[] = $attr_id;
$count_filter ++;
}
}
$product_filter_id_match = array();
if(sizeof($query_attr_id)) {
$query = $this->db->runQuery("
SELECT DISTINCT pro_id , COUNT(*) as num_pro
FROM ".TB_PRODUCT_ATTRIBUTE."
WHERE attr_value_id IN (".join(',', $query_attr_id).")
GROUP BY pro_id
HAVING num_pro = ".$count_filter."
LIMIT 10000
");
foreach ( $this->db->fetchAll($query) as $rs ) {
$product_filter_id_match[] = $rs["pro_id"];
}
}
$where_query[] = (sizeof($product_filter_id_match)) ? " AND `id` IN (".join(', ', $product_filter_id_match).") " : " AND `id` = 0 " ;
//xay lai url de back
if(!$this->objCategoryProduct) $this->objCategoryProduct = new CategoryProduct();
foreach($filter_attr_value_list as $value_id ){
$att_name = $this->objCategoryProduct->atrValueName($value_id);
$filterPath["attribute"][] = array(
"id" => $value_id,
"name" => $att_name,
);
$filter_messages[] = [
'title' => $att_name,
'reset' => Url::buildUrl($this->_request_url, ['filter' => join(FILTER_VALUE_SEPARATOR, remove_item_from_array($this->filters["attribute"], $value_id))] ),
];
}
}
*/
//- attribute values
if( array_key_exists("attribute", $this->filters) && sizeof($this->filters["attribute"])) {
$filter_attr_value_list = $this->filters["attribute"];
$attr_values_per_attribute = $this->groupAttributeValuesByAttributeId($filter_attr_value_list);
$having_match_count = sizeof(array_keys($attr_values_per_attribute));
$attribute_info_list = $this->groupAttributeListInfo(array_keys($attr_values_per_attribute));
$attr_where_query = [];
foreach ($attr_values_per_attribute as $_att_id => $_att_value_list) {
// if same attribute : find products that match either ONE of these values (not match ALL values)
$_att_info = $attribute_info_list[$_att_id];
if (!$_att_info) continue;
// this attribute requires all products must have ALL selected values
if ($_att_info['value_match_all'] && sizeof($_att_value_list) > 1) {
$_product_id_match_all = $this->getProductMatchAllAttributeValueIds($_att_value_list);
if (sizeof($_product_id_match_all) > 0) {
$attr_where_query[] = " ( `id` IN (" . join(",", $_product_id_match_all) . ") ) ";
} else {
$attr_where_query[] = " ( `id` = -1 ) ";
}
} else {
$attr_where_query[] = " ( SELECT DISTINCT `pro_id` FROM " . TB_PRODUCT_ATTRIBUTE . " WHERE (" .
join(" OR ", array_map(function ($_item) { return " `attr_value_id` = '" . intval($_item['id']) . "' "; }, $_att_value_list))
. " ) ) ";
}
}
$product_filter_id_match = array();
if (sizeof($attr_where_query)) {
$query = $this->db->runQuery("
SELECT `pro_id` , COUNT(*) AS num_pro
FROM ( " . join(" UNION ALL ", $attr_where_query) . " ) AS tpm_tb
GROUP BY pro_id
HAVING num_pro = " . $having_match_count . "
LIMIT 10000
");
foreach ($this->db->fetchAll($query) as $rs) {
$product_filter_id_match[] = $rs["pro_id"];
}
}
$where_query[] = (sizeof($product_filter_id_match)) ? " AND " . TB_PRODUCT_LIGHT . ".`id` IN (" . join(', ', $product_filter_id_match) . ") " : " AND " . TB_PRODUCT_LIGHT . ".`id` = 0 ";
//xay lai url de back
$objProductAttributeModel = new ProductAttributeModel();
foreach($filter_attr_value_list as $value_id ){
$att_name = $objProductAttributeModel->getInfo($value_id)['title'];
$filterPath["attribute"][] = array(
"id" => $value_id,
"name" => $att_name,
);
$filter_messages[] = [
'title' => $att_name,
'reset' => Url::buildUrl($this->_request_url, ['filter' => join(FILTER_VALUE_SEPARATOR, remove_item_from_array($this->filters["attribute"], $value_id))] ),
];
}
/*//xay lai url de back
$filterPath["attribute"] = $filter_attr_value_list;
foreach ($attr_values_per_attribute as $_att_id => $_att_value_list) {
foreach ($_att_value_list as $_item) {
$filter_messages[] = [
'title' => $_item['title'],
'reset' => Url::buildUrl(CURRENT_URL, ['filter' => join('-', remove_item_from_array($filter_attr_value_list, $_item['id']))]),
];
}
}*/
}
//given products' ids
if( array_key_exists("ids", $this->filters) && sizeof($this->filters["ids"])) {
$filter_messages[] = [
'title' => "IDs",
'reset' => Url::buildUrl($this->_request_url, ['ids' => '']),
];
$where_query[] = " AND `id` IN (". join(",", $this->filters["ids"]) .") ";
}
// exclude some ids
if( array_key_exists("excluded_ids", $this->filters) && sizeof($this->filters["excluded_ids"])) {
$filter_messages[] = [
'title' => "Excluded IDs",
'reset' => Url::buildUrl($this->_request_url, ['excluded_ids' => '']),
];
$where_query[] = " AND `id` NOT IN (". join(",", $this->filters["excluded_ids"]) .") ";
}
$price_range_query_limit = join(" ",$where_query);
//- price range
if(isset($this->filters["price"]) && sizeof($this->filters["price"]) && ($this->filters["price"]['min'] > 0 || $this->filters["price"]['max'] > 0)) {
//limit by price range
$maxPrice = clean_price($this->filters["price"]['max']);
$minPrice = clean_price($this->filters["price"]['min']);
$price_range_query = '';
if($maxPrice > 0 && $minPrice > 0){
$price_range_query = " ( `price` BETWEEN '".$minPrice."' AND '".$maxPrice."' ) ";
}else if($maxPrice > 0){
$price_range_query = " `price` < '".$maxPrice."' ";
}else if($minPrice > 0){
$price_range_query = " `price` >='".$minPrice."' ";
}
/*if(ENABLE_INVENTORY_PER_STORE && USER_LOCATION) {
$list_ids = $this->getProductIds($price_range_query_limit);
$this->objCache->set("all_product_ids_location", $list_ids);
$objUStoreLocation = new UStoreLocation();
$location_products = $objUStoreLocation->getAllProductForLocation(USER_LOCATION, $list_ids, $sort_by);
$location_products = $this->filterLocationProductByPrice($location_products, $maxPrice, $minPrice);
$this->objCache->set("location_products", $location_products);
$location_product_ids = array_keys($location_products);
$where_query[] = (sizeof($location_product_ids)) ? " AND `id` IN (".join(',', $location_product_ids).") " : " AND `id` = 0";
} else {
$where_query[] = " AND ". $price_range_query;
}*/
$where_query[] = " AND ". $price_range_query;
$filterPath["price"] = array(
"min" => $minPrice,
"max" => $maxPrice,
);
$price_format = ProductFilterPrice::buildPriceRangeFormat($minPrice, $maxPrice);
$filter_messages[] = [
'title' => $price_format['title'],
'reset' => Url::buildUrl($this->_request_url, ['p' => '', 'min' => '', 'max' => ''])
];
}
return [
$price_range_query_limit,
$filterPath,
$filter_messages,
$where_query
];
}
protected function getProductMatchAllAttributeValueIds(array $_att_value_list) {
$objProductAttributeModel = new ProductAttributeModel();
return $objProductAttributeModel->getProductMatchAllAttributeValueIds($_att_value_list);
}
protected function groupAttributeListInfo(array $attr_ids) {
$objProductAttributeModel = new ProductAttributeModel();
$attr_list_info = $objProductAttributeModel->getListByIds($attr_ids);
$final_list = [];
foreach ($attr_ids as $_id) {
$final_list[$_id] = (isset($attr_list_info[$_id])) ? $attr_list_info[$_id] : null;
}
return $final_list;
}
protected function groupAttributeValuesByAttributeId(array $attr_value_ids) {
$objProductAttributeValueModel = new ProductAttributeValueModel(0);
$result = array();
foreach ( $objProductAttributeValueModel->getListByIds($attr_value_ids) as $info ) {
$result[$info['attributeId']][] = [
'id' => $info['id'],
'title' => $info['value'],
];
}
return $result;
}
protected function filterLocationProductByPrice(array $product_list, $max_price, $min_price) {
if($max_price > 0 && $min_price > 0){
return array_filter($product_list, function ($pro) use ($max_price, $min_price) {
return ($pro['price'] >= $min_price && $pro['price'] < $max_price);
});
}
if($max_price > 0){
return array_filter($product_list, function ($pro) use ($max_price, $min_price) {
return ($pro['price'] < $max_price);
});
}
if($min_price > 0){
return array_filter($product_list, function ($pro) use ($max_price, $min_price) {
return ($pro['price'] >= $min_price);
});
}
return $product_list;
}
protected function getOrderingClause($sort_by) {
$mappings = [
'order-new' => "ORDER BY `ordering` DESC, `id` DESC",
'order-last-update' => "ORDER BY `ordering` DESC, last_update DESC",
'last-update' => "ORDER BY `last_update` DESC",
'order' => "ORDER BY `ordering` DESC",
'new' => "ORDER BY `id` DESC",
'price-asc' => "ORDER BY `price` asc",
'price-desc' => "ORDER BY `price` DESC ",
'view' => "ORDER BY `visit` desc",
'ranking' => "ORDER BY `ranking` DESC",
'name' => "ORDER BY `title` asc",
];
if(array_key_exists($sort_by, $mappings)) {
return $mappings[$sort_by];
}
return "ORDER BY `ordering` DESC, `id` DESC";
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\Components\Product\Model\ProductFilterModel;
class ProductFilterOptionsController {
protected $_current_category_ids = [];
protected $_list_product_ids = [];
protected $_price_range = [];// [1000000, 5000000, 15000000, 25000000, 50000000];
protected $_filters = [
"price" => array('max' => 0, 'min'=> 0),
"brand" => array(), // array(1,2,3,)
"collection" => array(), // array(1,2,3,)
"supplier" => array(), // array(1,2,3,)
"rating" => array(), // array(1,2,3,)
"category" => array(), // array(1,2,3,)
"status" => array(), // array(1,2,3,)
"query" => "", // string search keyword
"hotType" => array(),// array(saleoff | not | new)
"attribute" => array(), // array(1,2,3,)
"ids" => array(), // array(1,2,3,)
"promotion" => "",
"storeId" => array(), // array(1,2,3,)
"other_filter" => array() // array(in-stock, has-promotion etc...)
];
protected $objProductFilterModel;
public function __construct($filters, $current_category_ids = [], $list_product_ids = [], $price_range = []) {
$this->objProductFilterModel = new ProductFilterModel();
$this->_filters = $filters;
$this->_current_category_ids = $current_category_ids;
$this->_list_product_ids = $list_product_ids;
$this->_price_range = $price_range;
}
public function ratingList() {
$neededList = array();
foreach ( $this->objProductFilterModel->ratingList($this->_list_product_ids) as $result ) {
$neededList[] = array(
"rating" => $result['review_rate'] ,
"count" => $result['num'] ,
'is_selected' => in_array($result['review_rate'], $this->_filters['rating']),
);
}
return $neededList;
}
public function categoryList() {
if(!sizeof($this->_list_product_ids)) {
return [];
}
return $this->objProductFilterModel->categoryList($this->_filters['category'], $this->_list_product_ids);
}
public function brandList() {
if(!sizeof($this->_list_product_ids)) {
return [];
}
return $this->objProductFilterModel->brandList($this->_filters['brand'], $this->_list_product_ids);
}
public function attributeList() {
return $this->objProductFilterModel->attributeList(
$this->_filters['attribute'],
$this->_current_category_ids,
$this->_list_product_ids
);
}
public function priceList() {
return $this->objProductFilterModel->priceList(
$this->_filters['price']['max'] ,
$this->_filters['price']['min'],
$this->_list_product_ids,
$this->_price_range
);
}
}

View File

@@ -0,0 +1,348 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\System\Url;
class ProductFilterOptionsTranslationController {
protected $_request_url = '';
protected $_url_elements = [
'scheme' => '',
'host' => '',
'port' => '',
'user' => '',
'pass' => '',
'path' => '',
'query' => [],
'fragment' => '',
];
protected $_price_format = '';
protected $_brand_format = '';
protected $_filter_format = '';
public function __construct($request_url) {
if(defined('PRICE_FILTER_FORMAT') && PRICE_FILTER_FORMAT) {
$this->_price_format = PRICE_FILTER_FORMAT;
}
if(defined('BRAND_FILTER_FORMAT') && BRAND_FILTER_FORMAT) {
$this->_brand_format = BRAND_FILTER_FORMAT;
}
if(defined('ATTRIBUTE_FILTER_FORMAT') && ATTRIBUTE_FILTER_FORMAT ) {
$this->_filter_format = ATTRIBUTE_FILTER_FORMAT;
}
$this->_request_url = $request_url;
$this->_url_elements = Url::parse($request_url);
}
public function getAllFilterOptions(array $category_list = [], array $attribute_list = [], array $brand_list = [], array $price_list_options = []) {
$result = [
'category' => $category_list,
'price' => $this->translatePriceList($price_list_options),
'brand' => $this->translateBrandList($brand_list),
'attribute' => $this->translateAttributeList($attribute_list),
];
$selected_categories = array_filter($category_list, function ($item){ return $item['is_selected'];});
$selected_prices = array_filter($result['price'], function ($item){ return $item['is_selected'];});
$selected_brands = array_filter($result['brand'], function ($item){ return $item['is_selected'];});
$selected_attributes = array_filter($result['attribute'], function ($item){ return $item['is_selected'];});
$filter_messages = [];
foreach ($selected_categories as $selected_category) {
$filter_messages[] = [
'name' => $selected_category['name'], // 'Danh mục: '.
'reset_url' => Url::buildUrl($this->_request_url, ['category' => ''] ),
];
}
foreach ($selected_prices as $selected_price) {
$filter_messages[] = [
'name' => $selected_price['name'], // 'Giá: '.
'reset_url' => $selected_price['url'],
];
}
foreach ($selected_brands as $selected_brand) {
$filter_messages[] = [
'name' => $selected_brand['name'], // 'Thương hiệu: '.
'reset_url' => $selected_brand['url'],
];
}
foreach ($selected_attributes as $selected_attribute) {
$selected_attribute_values = array_filter($selected_attribute['value_list'], function ($item){ return $item['is_selected'];});
foreach ($selected_attribute_values as $selected_attribute_value) {
$filter_messages[] = [
'name' => $selected_attribute_value['name'], //$selected_attribute['name'].': '.$selected_attribute_value['name'],
'reset_url' => $selected_attribute_value['url'],
];
}
}
return [$result, $filter_messages];
}
public function translateAttributeList(array $attribute_list = []) {
$result = [];
foreach ($attribute_list as $attr_info) {
$copy = $attr_info;
$copy['value_list'] = array_map(function ($value_info) use ($attr_info) {
return $this->translateAttributeValue($attr_info['filter_code'], $value_info);
}, $attr_info['value_list']);
$result[] = $copy;
}
return $result;
}
protected function translateAttributeValue($attribute_filter_code, array $value_info = []) {
$copy = $value_info;
if($copy['is_selected']) {
$copy['url'] = Url::buildUrl($this->_request_url, $this->buildAttributeValueUrlResetParameters($attribute_filter_code, $value_info['id'], $value_info['api_key']) );
}else{
$copy['url'] = Url::buildUrl($this->_request_url, $this->buildAttributeValueUrlParameters($attribute_filter_code, $value_info['id'], $value_info['api_key']) );
}
//$copy['reset_url'] = Url::buildUrl($this->_request_url, $this->buildAttributeValueUrlResetParameters($attribute_filter_code, $value_info['id'], $value_info['api_key']) );
return $copy;
}
protected function buildAttributeValueUrlParameters($attribute_filter_code, $value_id, $value_api_key) {
if($this->_filter_format == 'filter_code') {
$filter_query = (isset($this->_url_elements['query'][$attribute_filter_code])) ? $this->_url_elements['query'][$attribute_filter_code] : '';
$filter_value_list = ($filter_query) ? explode(FILTER_VALUE_SEPARATOR, $filter_query) : [];
$filter_value_list[] = $value_api_key;
$result = [];
$result[$attribute_filter_code] = join(FILTER_VALUE_SEPARATOR, $filter_value_list );
return $result;
}
// default
$filter_query = (isset($this->_url_elements['query']['filter'])) ? $this->_url_elements['query']['filter'] : '';
$filter_value_list = ($filter_query) ? explode(FILTER_VALUE_SEPARATOR, $filter_query) : [];
$filter_value_list[] = $value_id;
sort($filter_value_list);
return [
'filter' => join(FILTER_VALUE_SEPARATOR, $filter_value_list ),
];
}
protected function buildAttributeValueUrlResetParameters($attribute_filter_code, $value_id, $value_api_key) {
if($this->_filter_format == 'filter_code') {
$filter_query = (isset($this->_url_elements['query'][$attribute_filter_code])) ? $this->_url_elements['query'][$attribute_filter_code] : '';
$filter_value_list = ($filter_query) ? explode(FILTER_VALUE_SEPARATOR, $filter_query) : [];
$filter_value_list = remove_item_from_array($filter_value_list, $value_api_key);
$result = [];
$result[$attribute_filter_code] = join(FILTER_VALUE_SEPARATOR, $filter_value_list );
return $result;
}
// default
$filter_query = (isset($this->_url_elements['query']['filter'])) ? $this->_url_elements['query']['filter'] : '';
$filter_value_list = ($filter_query) ? explode(FILTER_VALUE_SEPARATOR, $filter_query) : [];
$filter_value_list = remove_item_from_array($filter_value_list, $value_id);
return [
'filter' => join(FILTER_VALUE_SEPARATOR, $filter_value_list ),
];
}
public function translateBrandList(array $brand_list = []) {
return array_map(function ($item){
$copy = $item;
if(($copy['is_selected'])) {
$copy['url'] = Url::buildUrl($this->_request_url, $this->buildBrandUrlResetParameters($item['id'], $item['brand_index']) ) ;
}else{
$copy['url'] = Url::buildUrl($this->_request_url, $this->buildBrandUrlParameters($item['id'], $item['brand_index']) );
}
//$copy['reset_url'] = Url::buildUrl($this->_request_url, $this->buildBrandUrlResetParameters($item['id'], $item['brand_index']) );
//unset($copy['brand_index']);
return $copy;
}, $brand_list);
}
protected function buildBrandUrlResetParameters($brand_id, $brand_index){
$brand_query = (isset($this->_url_elements['query']['brand'])) ? $this->_url_elements['query']['brand'] : '';
$brand_list = ($brand_query) ? explode(FILTER_VALUE_SEPARATOR, $brand_query) : [];
if($this->_brand_format == 'brand_index') {
$brand_list = remove_item_from_array($brand_list, $brand_index);
}else{
$brand_list = remove_item_from_array($brand_list, $brand_id);
}
return [
'brand' => join(FILTER_VALUE_SEPARATOR, $brand_list ),
];
}
protected function buildBrandUrlParameters($brand_id, $brand_index){
$brand_query = (isset($this->_url_elements['query']['brand'])) ? $this->_url_elements['query']['brand'] : '';
$brand_list = ($brand_query) ? explode(FILTER_VALUE_SEPARATOR, $brand_query) : [];
if($this->_brand_format == 'brand_index') {
if(!in_array($brand_index, $brand_list)) $brand_list[] = $brand_index;
}else{
if(!in_array($brand_id, $brand_list)) $brand_list[] = $brand_id;
}
return [
'brand' => join(FILTER_VALUE_SEPARATOR, $brand_list ),
];
}
public function translatePriceList(array $price_list_options = []) {
return array_map(function ($item){
$copy = $item;
$format = $this->buildPriceRangeFormat($item['min'], $item['max']);
$copy['name'] = $format['name'];
$copy['url'] = ($copy['is_selected']) ? Url::buildUrl($this->_request_url, $this->buildPriceUrlResetParameters()) : Url::buildUrl($this->_request_url, $format['url_para']);
//$copy['reset_url'] = Url::buildUrl($this->_request_url, $this->buildPriceUrlResetParameters());
//unset($copy['min'], $copy['max']);
return $copy;
}, $price_list_options);
}
protected function buildPriceRangeFormat($min_price, $max_price) {
if($min_price > 0 && !$max_price) {
$title = "Trên ".$this->format_search_price($min_price);
}elseif(!$min_price && $max_price > 0) {
$title = "Dưới ".$this->format_search_price($max_price);
}else{
$title = $this->format_search_price($min_price)." - ".$this->format_search_price($max_price);
}
return [
'url_para' => $this->buildPriceUrlParameters($min_price, $max_price),
'name' => $title,
];
}
protected function format_search_price($p_price){
$price_len = strlen($p_price);
if($price_len < 7) {
return round($p_price/1000,1)." ngàn";
}
else if($price_len < 10) {
return round($p_price/1000000,1)." triệu";
}
return round($p_price/1000000000,1)." tỷ";
}
protected function buildPriceUrlResetParameters() {
if( $this->_price_format == 'p') {
return [
"p" => '',
];
}
return [
"min" => '' ,
"max" => '' ,
];
}
protected function buildPriceUrlParameters($min_price = 0, $max_price = 0) {
if($min_price > 0 && !$max_price) {
if( $this->_price_format == 'p') {
return [
"p" => "tren-".self::convertPriceFormatToFilter($this->format_search_price($min_price)),
];
}
return [
"min" => $min_price ,
];
}
if(!$min_price && $max_price > 0) {
if( $this->_price_format == 'p') {
return [
"p" => "duoi-" . self::convertPriceFormatToFilter($this->format_search_price($max_price)),
];
}
return [
"max" => $max_price,
];
}
if( $this->_price_format == 'p') {
return [
"p" => self::convertPriceFormatToFilter($this->format_search_price($min_price)) . "-" . self::convertPriceFormatToFilter($this->format_search_price($max_price)),
];
}
return [
"max" => $max_price ,
"min" => $min_price,
];
}
// convert: 10 ngàn -> 10ngan, 10 triệu => 10trieu
protected static function convertPriceFormatToFilter($price_format){
$price_format = str_replace(['ngàn', 'triệu'], ['ngan', 'trieu'], $price_format);
// remove whitespace
return str_replace(" ",'', $price_format);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\Components\Product\Model\ProductCategoryLanguageModel;
use Hura8\Components\Product\Model\ProductCategoryModel;
use Hura8\System\Controller\aCategoryBaseController;
class bProductCategoryController extends aCategoryBaseController
{
static $image_folder = "media/category";
protected $objProductCategoryModel;
public function __construct()
{
$this->objProductCategoryModel = new ProductCategoryModel();
if(!$this->isDefaultLanguage()) {
//$this->objProductCategoryLanguageModel->createTableLang();
parent::__construct(
$this->objProductCategoryModel,
new ProductCategoryLanguageModel()
);
}else{
parent::__construct(
$this->objProductCategoryModel
);
}
}
protected function formatItemInfo(?array $info) : ?array
{
if(!$info) return null;
if($info['icon']) $info['icon'] = STATIC_DOMAIN . "/" . static::$image_folder . "/" . $info['icon'];
return $info;
}
// get full info- basic with description
public function getFullInfo($id): ?array
{
$info = $this->objProductCategoryModel->getFullInfo($id);
if(!$info) return null;
if($this->iEntityLanguageModel) {
$item_language_info = $this->iEntityLanguageModel->getInfo($id);
if($item_language_info) {
return $this->formatItemInfo(array_merge($info, $item_language_info));
}
}
return $this->formatItemInfo($info);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\Components\Product\Model\ProductCollectionLanguageModel;
use Hura8\Components\Product\Model\ProductCollectionModel;
use Hura8\System\Controller\aCategoryBaseController;
class bProductCollectionController extends aCategoryBaseController
{
static $image_folder = "media/category";
protected $objProductCollectionModel;
public function __construct()
{
$this->objProductCollectionModel = new ProductCollectionModel();
if(!$this->isDefaultLanguage()) {
//$this->objProductCategoryLanguageModel->createTableLang();
parent::__construct(
$this->objProductCollectionModel,
new ProductCollectionLanguageModel()
);
}else{
parent::__construct(
$this->objProductCollectionModel
);
}
}
public function getTotalProduct($collection_id, array $condition = [])
{
return $this->objProductCollectionModel->getTotalProduct($collection_id, $condition);
}
public function getListProduct($collection_id, array $condition = []) {
return $this->objProductCollectionModel->getListProduct($collection_id, $condition);
}
protected function formatItemInList(array $info) : array
{
return $this->formatItemInfo($info);
}
protected function formatItemInfo(?array $info) : ?array
{
$info['url'] = "/collection/".$info['url_index'];
return $info;
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace Hura8\Components\Product\Controller;
use Hura8\Components\Product\Model\ProductImageModel;
use Hura8\Components\Product\Model\ProductLanguageModel;
use Hura8\Components\Product\Model\ProductModel;
use Hura8\System\Controller\aEntityBaseController;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
use Hura8\System\Url;
abstract class bProductController extends aEntityBaseController
{
static $image_folder = "media/product";
static $resized_sizes = array(
't' => ['width' => 100,] ,
's' => ['width' => 300,] ,
'l' => ['width' => 650,]
);
protected $objProductModel;
public function __construct()
{
$this->objProductModel = new ProductModel();
if(!$this->isDefaultLanguage()) {
$objProductLanguageModel = new ProductLanguageModel();
// $this->objProductLanguageModel->createTableLang();
parent::__construct($this->objProductModel, $objProductLanguageModel);
}else{
parent::__construct($this->objProductModel);
}
}
//get product image list
public function productImageList($proId){
$objProductImageModel = new ProductImageModel($proId);
$result = array();
foreach ( $objProductImageModel->getList(["numPerPage" => 100]) as $rs ) {
$result[] = [
"size" => static::getResizedImageCollection($rs['img_name']),
"alt" => $rs['alt'],
"folder" => $rs['folder'],
];
}
return $result;
}
public function getProductDisplayOptions($current_url) {
$allowed_options = array(
"list" => "Danh sách",
"grid" => "Xem nhóm",
"detail" => "Chi tiết"
) ;
$collection = array();
foreach($allowed_options as $option => $name){
$url = Url::buildUrl($current_url, array("display" => ""));
$collection[] = array(
"url" => Url::buildUrl($url, array("display" => $option)) ,
"key" => $option ,
"name" => $name ,
);
}
return $collection;
}
public function getProductOtherFilterOptions($current_url) {
$allowed_options = array(
//"order" => $global_language['sort_by_order'] ,
"in-stock" => 'Còn hàng' ,
) ;
$_collection = array();
foreach($allowed_options as $option => $_name){
$_collection[] = array(
"url" => Url::buildUrl($current_url, array("other_filter" => $option, 'page' => '')) ,
"key" => $option ,
"name" => $_name ,
);
}
return $_collection;
}
public function getProductSortOptions($current_url, array $options = []) {
//global $global_language;
if(!sizeof($options)) $options = array(
//"order" => $global_language['sort_by_order'] ,
"new" => "Mới nhất" ,
"price-asc" => "Giá tăng dần", //$global_language['sort_by_price_asc'] ,
"price-desc" => "Giá giảm dần", //$global_language['sort_by_price_desc'] ,
"view" => "Lượt xem", //$global_language['sort_by_view'],
"comment" => "Trao đổi", //$global_language['sort_by_comment'] ,
"rating" => "Đánh giá", //$global_language['sort_by_rating'] ,
"name" => "Tên A->Z" ,
) ;
$sort_by_collection = array();
foreach($options as $sort_option=>$sort_name){
// $url = build_url($current_url, array("sort" => ""));
$sort_by_collection[] = array(
"url" => Url::buildUrl($current_url, array("sort" => $sort_option)) ,
"key" => $sort_option ,
"name" => $sort_name ,
);
}
return $sort_by_collection;
}
public function getProductInfoBySKU($sku) {
return self::getCache(md5("getFullInfo-".$sku), function () use ($sku) {
$info = $this->objProductModel->getProductInfoBySKU($sku);
return ($info) ? $this->formatItemInfo($info) : null;
});
}
// get full info- basic with description
public function getFullInfo($id)
{
return self::getCache("getFullInfo-".$id, function () use ($id) {
$info = $this->objProductModel->getFullInfo($id);
if($this->iEntityLanguageModel && $info) {
$item_language_info = $this->iEntityLanguageModel->getInfo($id);
if($item_language_info) {
return $this->formatItemInfo(array_merge($info, $item_language_info));
}
}
return ($info) ? $this->formatItemInfo($info) : null;
});
}
protected function validateAndCleanFilterCondition(array $raw_filter_condition): array
{
$clean_values = parent::validateAndCleanFilterCondition($raw_filter_condition);
// special cases for 'price' which is in range
if(array_key_exists('price', $raw_filter_condition)) {
$value = $raw_filter_condition['price'];
// expect $value = array('max' => 0, 'min'=> 0)
if(isset($value['max']) && isset($value['min'])) {
$clean_values['price'] = array(
'max' => DataClean::makeInputSafe($value['max'], DataType::INTEGER),
'min' => DataClean::makeInputSafe($value['min'], DataType::INTEGER),
);
}
}
return $clean_values;
}
protected function formatItemInList(array $item_info) : array
{
return $this->formatItemInfo($item_info);
}
protected function formatItemInfo(?array $item_info): ?array
{
if(!$item_info) return null;
$info = $item_info;
$info['image'] = static::getResizedImageCollection($info['thumbnail']);
return $info;
}
public static function getResizedImageCollection($image_name) {
$image = [];
$size_in_full = [
't' => 'thumb' ,
's' => 'small' ,
'l' => 'large' ,
];
foreach (static::$resized_sizes as $size => $value) {
$image[$size_in_full[$size]] = ($image_name) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $image_name : '';
}
$image['original'] = ($image_name) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $image_name : '';
return $image;
}
}