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,16 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\System\Model\EntityLanguageModel;
use Hura8\Interfaces\EntityType;
class ProductAttributeLanguageModel extends EntityLanguageModel
{
public function __construct() {
parent::__construct(EntityType::PRODUCT_ATTRIBUTE);
}
}

View File

@@ -0,0 +1,175 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Language;
use Hura8\System\Model\aEntityBaseModel;
use Hura8\Interfaces\iEntityModel;
use Hura8\Interfaces\EntityType;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
class ProductAttributeModel extends aEntityBaseModel {
protected $tb_product_category = "tb_product_category";
protected $tb_attribute_value = "tb_attribute_value";
protected $tb_product_spec_group = "tb_product_spec_group";
protected $tb_attribute_per_spec_group = "tb_attribute_per_spec_group";
protected $tb_attribute_per_category = "tb_attribute_per_category";
public function __construct() {
parent::__construct(EntityType::PRODUCT_ATTRIBUTE);
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
// SPEC-GROUP
public function getSpecGroupAttributeWithValues($group_id) {
$query = $this->db->runQuery(
"SELECT
a.title,
a.summary,
a.is_filter,
a.value_match_all,
a.filter_code,
a.is_display,
a.is_header,
a.is_multi, a.in_summary,
a.value_count,
g.attr_id,
g.ordering,
g.status
FROM ".$this->tb_attribute_per_spec_group." g, ".$this->tb_entity." a
WHERE g.`group_id`= ? AND g.`attr_id`= a.`id`
ORDER BY g.`ordering` DESC, a.`ordering` DESC ",
['d'],
[$group_id]
) ;
$attribute_ids = [];
$value_per_attribute_ids = [];
$result = [];
foreach ($this->db->fetchAll($query) as $item) {
$attribute_ids[] = $item['attr_id'];
$value_per_attribute_ids[$item['attr_id']] = [];
$result[$item['attr_id']] = [
"attribute_info" => $item,
"attribute_values" => &$value_per_attribute_ids[$item['attr_id']],
];
}
if(!sizeof($attribute_ids)) {
return [];
}
// now get all values for each attribute
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($attribute_ids, "int");
$query = $this->db->runQuery(
"SELECT * FROM ".$this->tb_attribute_value."
WHERE `attribute_id` IN (".$parameterized_ids.")
ORDER BY `ordering` DESC, `title` ASC ",
$bind_types,
$attribute_ids
) ;
foreach ($this->db->fetchAll($query) as $item) {
$value_per_attribute_ids[$item['attribute_id']][] = $item;
}
return $result;
}
public function getSpecGroupAttribute($group_id) {
$query = $this->db->runQuery(
"SELECT
a.title,
a.summary,
a.is_filter,
a.value_match_all,
a.filter_code,
a.is_display,
a.is_header, a.is_multi, a.value_count,
g.attr_id,
g.ordering,
g.status
FROM ".$this->tb_attribute_per_spec_group." g, ".$this->tb_entity." a
WHERE g.`group_id`= ? AND g.`attr_id`= a.`id`
ORDER BY g.`ordering` DESC, a.`ordering` DESC ",
['d'],
[$group_id]
) ;
return $this->db->fetchAll($query);
}
public function getProductMatchAllAttributeValueIds(array $_att_value_list) {
/*$query = $this->db->runQuery("
SELECT `pro_id` , COUNT(*) AS num_pro
FROM ".TB_PRODUCT_ATTRIBUTE."
WHERE " . join(" OR ", array_map(function ($_item){ return " `attr_value_id` = '".intval($_item['id'])."' "; }, $_att_value_list )) ."
GROUP BY pro_id
HAVING num_pro = ".sizeof($_att_value_list)."
LIMIT 10000
");
return array_map(function ($item){
return $item["pro_id"];
}, $this->db->fetchAll($query));*/
return [];
}
public function getProductMatchAttributeValue(array $value_ids) {
$product_filter_id_match = array();
// todo:
/*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"];
}
}*/
return $product_filter_id_match;
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
/*$condition = array(
"q" => "",
"letter" => "",
"status" => 0,
);*/
$catCondition = [];
$bind_types = [];
$bind_values = [];
return array( join(" ", $catCondition), $bind_types, $bind_values);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;
use Hura8\Interfaces\EntityType;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
class ProductAttributeValueModel extends aEntityBaseModel
{
const MAX_VALUE_PER_ATTRIBUTE = 100; // one attribute should not have more that this number of values
protected $attribute_id = 0;
protected $tb_attribute = 'tb_attribute';
protected $tb_product_attribute = 'tb_product_attribute';
public function __construct($attribute_id) {
parent::__construct(EntityType::PRODUCT_ATTRIBUTE_VALUE);
$this->attribute_id = $attribute_id;
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
public function getProductAttributes($product_id) {
$query = $this->db->runQuery(
"SELECT `attr_id`, `attr_value_id` FROM `".$this->tb_product_attribute."` WHERE `pro_id` = ? ",
['d'], [ $product_id]
);
return $this->db->fetchAll($query);
}
protected function getAttributeValueCount() {
$query = $this->db->runQuery(
"SELECT `value_count` FROM `".$this->tb_attribute."` WHERE `id` = ? LIMIT 1 ",
['d'], [$this->attribute_id]
);
if($info = $this->db->fetchAssoc($query)) {
return $info['value_count'];
}
return 0;
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
$catCondition = [" AND `attribute_id` = ? "];
$bind_types = ["d"];
$bind_values = [$this->attribute_id];
return array( join(" ", $catCondition), $bind_types, $bind_values);
}
public function getInfoByCode($filter_code)
{
$query = $this->db->runQuery(
"SELECT * FROM `".$this->tb_entity."` WHERE `attribute_id` = ? AND `filter_code` = ? LIMIT 1",
['d', 's'], [$this->attribute_id, $filter_code ]
);
return $this->db->fetchAssoc($query);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Database\iConnectDB;
class ProductCategoryInfoModel
{
/* @var $db iConnectDB */
protected $db;
protected $tb_category_info = "tb_product_category_info";
public function __construct() {
$this->db = get_db();
}
public function getInfo($id) {
return $this->db->select(
$this->tb_category_info,
[],
[
'id' => ['=', $id],
]
);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\System\Model\EntityLanguageModel;
use Hura8\Interfaces\EntityType;
class ProductCategoryLanguageModel extends EntityLanguageModel
{
protected $richtext_fields = [
'description',
];
public function __construct() {
parent::__construct(EntityType::PRODUCT_CATEGORY, '', $this->richtext_fields);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Controller\UrlManagerController;
use Hura8\System\Model\aCategoryBaseModel;
use Hura8\System\ModuleManager;
use Hura8\Interfaces\EntityType;
class ProductCategoryModel extends aCategoryBaseModel
{
static $url_module = "product";
static $url_view = "category";
static $url_type = "product:category";
protected $tb_category_info = "tb_product_category_info";
protected $tb_product_per_category = "tb_product_per_category";
protected $tb_attribute_per_category = "tb_attribute_per_category";
protected $tb_attribute_value = "tb_attribute_value";
protected $tb_attribute = "tb_attribute";
public function __construct() {
parent::__construct(EntityType::PRODUCT_CATEGORY);
}
public function getAttributeList($catId) {
$query = $this->db->runQuery("SELECT
a.id ,
a.filter_code ,
a.title ,
a.value_count ,
a.is_filter ,
c.ordering ,
c.status ,
a.is_header
FROM ".$this->tb_attribute." a
LEFT JOIN ".$this->tb_attribute_per_category." c ON a.id = c.attr_id
WHERE c.category_id = ?
ORDER BY c.ordering desc
", ['d'], [ $catId ]) ; // AND isSearch = 1
return $this->db->fetchAll($query);
}
public function getFullInfo($id) : ?array {
$query = $this->db->runQuery(
"SELECT * FROM `".$this->tb_entity."` basic, `".$this->tb_category_info."` info
WHERE basic.`id` = info.`id` AND basic.id = ?
LIMIT 1 ",
['d'], [$id]
);
if( $item_info = $this->db->fetchAssoc($query)){
$item_info['settings'] = ($item_info['settings']) ? \json_decode($item_info['settings'], true) : [];
return $item_info;
}
return null;
}
public function getEmptyInfo($addition_field_value = []) : array
{
// basic table
$basic_empty = parent::getEmptyInfo($addition_field_value);
// info table
foreach ($this->db->getTableInfo($this->tb_category_info) as $field => $field_info) {
$basic_empty[$field] = ( in_array($field_info['DATA_TYPE'], ['int', 'float']) ) ? 0 : '' ;
}
if(sizeof($addition_field_value)) {
return array_merge($basic_empty, $addition_field_value);
}
return $basic_empty;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\EntityType;
use Hura8\System\Model\EntityLanguageModel;
class ProductCollectionLanguageModel extends EntityLanguageModel
{
protected $richtext_fields = [
'description',
];
public function __construct() {
parent::__construct(EntityType::PRODUCT_COLLECTION, '', $this->richtext_fields);
//$this->createTableLang();
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\EntityType;
use Hura8\System\Model\aCategoryBaseModel;
class ProductCollectionModel extends aCategoryBaseModel
{
protected $tb_collection_product = "tb_collection_product";
public function __construct() {
parent::__construct(EntityType::PRODUCT_COLLECTION);
}
public function getInfoByUrl($url): ?array
{
$query = $this->db->runQuery(
" SELECT * FROM `".$this->tb_entity."` WHERE `url_index` = ? LIMIT 1",
['s'], [$url]
);
return $this->db->fetchAssoc($query);
}
public function getTotalProduct($collection_id, array $condition = [])
{
$query = $this->db->runQuery(
" SELECT COUNT(*) as total FROM `".$this->tb_collection_product."` WHERE `collection_id` = ? ",
['d'], [$collection_id]
);
$total = 0;
if ($rs = $this->db->fetchAssoc($query)) {
$total = $rs['total'];
}
return $total;
}
public function getListProduct($collection_id, array $condition = [])
{
$numPerPage = (isset($condition['numPerPage']) && $condition['numPerPage'] > 0 ) ? intval($condition['numPerPage']) : 20 ;
$page = (isset($condition['page']) && $condition['page'] > 0 ) ? intval($condition['page']) : 1 ;
$order_by = " `ordering` DESC, `id` DESC";
$query = $this->db->runQuery(
"SELECT `product_id`, `ordering` FROM ".$this->tb_collection_product." WHERE `collection_id` = ?
ORDER BY ".$order_by."
LIMIT ".(($page-1) * $numPerPage).", ".$numPerPage ,
['d'], [$collection_id]
) ;
$item_list = array();
$counter = ($page-1) * $numPerPage;
foreach ( $this->db->fetchAll($query) as $item ) {
$counter += 1;
$item_list[$item['product_id']] = [
'counter' => $counter,
'ordering' => $item['ordering'],
];
}
$objProductModel = new ProductModel();
$product_list_info = $objProductModel->getListByIds(array_keys($item_list));
// final list
$final_list = [];
foreach ($item_list as $_pro_id => $_pro_info_in_collection) {
$pro_basic = $product_list_info[$_pro_id] ?? null;
if($pro_basic) {
$final_list[] = array_merge($pro_basic, $_pro_info_in_collection);
}
}
return $final_list;
}
}

View File

@@ -0,0 +1,452 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Components\Brand\Model\BrandModel;
use Hura8\Database\iConnectDB;
use Hura8\Interfaces\TableName;
use Hura8\Traits\ClassCacheTrait;
class ProductFilterModel
{
use ClassCacheTrait;
/* @var $db iConnectDB */
protected $db;
public function __construct() {
$this->db = get_db('', ENABLE_DB_DEBUG);
}
public function findProductListIdMatchFilters(array $SQLConditionFromFilters) {
list(
$where_query,
$current_page_id,
$number_per_page,
$ordering_clause
) = $SQLConditionFromFilters;
$db_condition = join(" ", $where_query);
$total_number = 0;
$query = $this->db->runQuery("SELECT COUNT(`id`) AS total FROM ".TableName::PRODUCT." WHERE 1 ".$db_condition." ");
if($rs = $this->db->fetchAssoc($query)) {
$total_number = $rs['total'];
}
$query = $this->db->runQuery("
SELECT * FROM ".TableName::PRODUCT."
WHERE 1 ".$db_condition."
".$ordering_clause."
LIMIT ". ($current_page_id - 1) * $number_per_page .", ".$number_per_page."
");
$item_list = $this->db->fetchAll($query);
return [$total_number, $item_list];
}
public function ratingList(array $list_product_ids) {
if(!sizeof($list_product_ids)) return [];
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($list_product_ids, 'int');
$query = $this->db->runQuery(
"
SELECT `review_rate`, COUNT(`id`) as num
FROM ".TableName::PRODUCT."
WHERE `id` IN (".$parameterized_ids.")
GROUP BY `review_rate`
ORDER BY review_rate ASC
",
$bind_types,
$list_product_ids
);
return $this->db->fetchAll($query);
}
public function categoryList(array $current_category_ids, array $list_product_ids) {
if(!sizeof($list_product_ids)) {
return [];
}
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($list_product_ids, 'int');
$query = $this->db->runQuery(
"
SELECT `category_id`, COUNT(`item_id`) AS numPro
FROM ".TableName::PRODUCT_PER_CATEGORY."
WHERE `item_id` IN (".$parameterized_ids.")
GROUP BY `category_id` ",
$bind_types,
$list_product_ids
);
//lay ket qua dem
$result_count = [];
foreach ($this->db->fetchAll($query) as $rs ){
$result_count[$rs['category_id']] = $rs['numPro'];
}
if(sizeof($result_count)) {
$objProductCategoryModel = new ProductCategoryModel();
$final_result = [];
foreach ($objProductCategoryModel->getListByIds(array_keys($result_count)) as $rs ){
$rs['count'] = $result_count[$rs['id']];
$rs['is_selected'] = in_array($rs['id'], $current_category_ids);
$final_result[] = $rs;
}
return $final_result;
}
return [];
}
public function brandList(array $current_brand_ids, array $list_product_ids) {
if(!sizeof($list_product_ids)) {
return [];
}
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($list_product_ids, 'int');
$query = $this->db->runQuery(
" SELECT `brand_id`, COUNT(`id`) AS total
FROM ".TableName::PRODUCT."
WHERE `id` IN (".$parameterized_ids.")
GROUP BY `brand_id`
ORDER BY total DESC
LIMIT 100",
$bind_types,
$list_product_ids
);
$neededList = array();
foreach ( $this->db->fetchAll($query) as $result ) {
$neededList[$result['brand_id']] = array(
"id" => $result['brand_id'] ,
"count" => $result['total'] ,
);
}
$brand_list_ids[] = array_keys($neededList);
$result_list = array();
if(sizeof($brand_list_ids)) {
$objBrandModel = new BrandModel();
foreach ( $objBrandModel->getListByIds($brand_list_ids) as $_brand ) {
$item_count = (isset($neededList[$_brand['id']])) ? $neededList[$_brand['id']]['count'] : 0;
$_brand['count'] = $item_count;
$_brand["is_selected"] = in_array($_brand['id'], $current_brand_ids);
$result_list[$_brand['id']] = $_brand;
}
}
return array_values($result_list);
}
public function attributeList(array $current_filter_attribute_value_ids, array $current_category_ids, array $list_product_ids) {
if(!sizeof($list_product_ids)) {
return [];
}
$category_attribute_filter_array = $this->countNumProPerAttributeForCategory($current_category_ids, $list_product_ids);
if(!sizeof($category_attribute_filter_array)) {
return [];
}
$filter_box = array();
foreach($category_attribute_filter_array as $attributeIdGroup){
$attribute_value_array = $attributeIdGroup['value_list'];
$attribute_name = $attributeIdGroup['name'];
$attribute_selected = 0;
$filterList = array();
$count_num = 0;
foreach($attribute_value_array as $att_value_id => $rs_value){
$att_value_name = $rs_value["info"]["name"];
$att_value_description = $rs_value["info"]["description"];
$count_pro = $rs_value["pro_count"];
$is_selected = in_array($att_value_id, $current_filter_attribute_value_ids);
if($is_selected) {
$attribute_selected = 1;
}
unset($this_filter_query, $this_filter_col_value);
//gioi han danh sach
if($count_num > 50) {
break;
}
$count_num++;
$filterList[] = array(
"id" => $att_value_id ,
"name" => $att_value_name ,
'api_key' => $rs_value["info"]["api_key"],
"description" => $att_value_description,
"count" => $count_pro ,
"is_selected" => $is_selected,
);
}
if($count_num > 0){
$filter_box[] = [
"name" => $attribute_name,
'filter_code' => $attributeIdGroup['filter_code'],
"is_selected" => $attribute_selected,
"value_list" => $filterList ,
];
}
}
return $filter_box;
}
protected function countNumProPerAttributeForCategory(array $current_category_ids, array $list_product_ids){
if(!sizeof($list_product_ids)) {
return [];
}
$category_attributes = $this->getAttributesForCategory($current_category_ids);
$att_value_id_list = [];
foreach ($category_attributes as $attribute) {
$att_value_id_list = array_merge($att_value_id_list, array_keys($attribute['value_list']));
}
// count product per attribute-value-id
$result_count = array();
if(sizeof($att_value_id_list)) {
$query = $this->db->runQuery("
SELECT
pro_att.`attr_value_id`,
COUNT(DISTINCT ".TB_PRODUCT_CATEGORY.".pro_id) AS numPro
FROM ".TB_PRODUCT_ATTRIBUTE." pro_att
LEFT JOIN ".TB_PRODUCT_CATEGORY." ON pro_att.pro_id = ".TB_PRODUCT_CATEGORY.".pro_id
WHERE pro_att.pro_id IN (".join(',', $list_product_ids ).")
AND pro_att.`attr_value_id` IN (".join(",", $att_value_id_list).")
GROUP BY pro_att.`attr_value_id` ");
//lay ket qua dem
foreach ($this->db->fetchAll($query) as $rs ){
$result_count[$rs['attr_value_id']] = $rs['numPro'];
}
}
$final_result = [];
foreach ($category_attributes as $attribute) {
$new_value_list = [];
foreach ($attribute['value_list'] as $_value_id => $_value_info) {
$pro_count = isset($result_count[$_value_id]) ? $result_count[$_value_id] : 0;
if($pro_count) {
$_value_info['pro_count'] = $pro_count;
$new_value_list[$_value_id] = $_value_info;
}
}
$attribute['value_list'] = $new_value_list;
$final_result[] = $attribute;
}
return $final_result;
}
// 15-07-2020 get all attributes and values for a list of category
protected function getAttributesForCategory(array $category_ids){
if(!sizeof($category_ids)) {
return array();
}
$final_result = array();//array to return
$category_att_id_list = array();
$attribute_array = array(); //keep & re-order attribute
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($category_ids, 'int');
$query = $this->db->runQuery("
SELECT `attr_id`, `ordering` FROM `idv_attribute_category`
WHERE `category_id` IN (". $parameterized_ids .") AND `status` = 1 ", $bind_types, $category_ids);
foreach ($this->db->fetchAll($query) as $rs ){
$category_att_id_list[] = $rs['attr_id'];
$attribute_array[$rs['attr_id']] = $rs['ordering'];
}
if(!sizeof($category_att_id_list)) {
return array();
}
$att_value_id_list = array();
$attribute_info = array();
$attribute_att_value_item = array();
$attribute_value_info = array();
$query = $this->db->runQuery("
SELECT
attval.id ,
attval.attributeId ,
attval.value ,
attval.description ,
attval.api_key ,
attval.value_en ,
att.attribute_code ,
att.filter_code,
att.name ,
att.ordering
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 ");
foreach ($this->db->fetchAll($query) as $rs ){
$att_value_id = $rs['id'];
$att_id = $rs['attributeId'];
$att_value_id_list[] = $att_value_id;
$attribute_att_value_item[$att_id][] = $att_value_id; //in ordering
$attribute_info[$att_id] = array(
"id" => $att_id,
"name" => $rs['name'],
"code" => $rs['attribute_code'],
"filter_code" => $rs['filter_code'],
);
$attribute_value_info[$att_value_id] = array(
"id" => $att_value_id,
"name" => $rs['value'],
"description" => $rs['description'],
"api_key" => $rs['api_key'],
);
}
//cho ra ket qua
arsort($attribute_array); //sap xep thu tu cua attribute theo ordering
foreach($attribute_array as $att_id => $att_order){
$this_attribute_atr_value_item = array();
if(isset($attribute_att_value_item[$att_id])) {
foreach($attribute_att_value_item[$att_id] as $att_value_id){
$this_attribute_atr_value_item[$att_value_id] = array(
"id" => $att_value_id,
"info" => $attribute_value_info[$att_value_id],
);
}
}
if(isset($attribute_info[$att_id])) {
$info = $attribute_info[$att_id];
$info['value_list'] = $this_attribute_atr_value_item;
$final_result[] = $info;
}
}
return $final_result;
}
public function priceList($current_max_price, $current_min_price, array $list_product_ids, array $category_price_range) {
if(!sizeof($list_product_ids)) {
return [];
}
$total_prices = sizeof($category_price_range);
if( ! $total_prices ){
return [];
}
//pad head and tail with 0
array_unshift($category_price_range, 0);
$category_price_range[] = 0;
$result = array();
$queries = [];
for($i = 0; $i <= $total_prices ; $i++){
$range_key = md5($category_price_range[$i] .'-'. $category_price_range[$i+1] );
$queries[] = $this->buildRangeQuery($list_product_ids, $range_key, $category_price_range[$i], $category_price_range[$i+1]);
$min_price = intval($category_price_range[$i]);
$max_price = intval($category_price_range[$i+1]);
$is_selected = ($max_price == $current_max_price && $min_price == $current_min_price );
$result[$range_key] = array(
"min" => $min_price ,
"max" => $max_price,
"count" => 0 ,
"is_selected" => ($is_selected) ? 1 : 0 ,
);
}
$query = $this->db->runQuery(" SELECT `range_key`, `total` FROM ( ".join(' UNION ALL ', $queries)." ) AS tmp");
foreach ($this->db->fetchAll($query) as $rs) {
$result[$rs['range_key']]['count'] = $rs['total'];
}
// get only range with product-count > 0
return array_values(array_filter( $result , function ($item){
return $item['count'] > 0;
}));
}
private function buildRangeQuery(array $list_product_ids, $range_key, $minPrice, $maxPrice){
$minPrice = (int) $minPrice;
$maxPrice = (int) $maxPrice;
if($minPrice < 10) $minPrice = 10;
$new_price_range = " AND `id` IN (".join(',', $list_product_ids ).") ";
if($maxPrice > 0 && $minPrice > 0){
$new_price_range .= " AND ( `price` BETWEEN '".$minPrice."' AND '".$maxPrice."' ) ";
}elseif($maxPrice > 0){
$new_price_range .= " AND `price` < '".$maxPrice."' ";
}elseif($minPrice > 0 && $maxPrice == 0){
$new_price_range .= " AND `price` >='".$minPrice."' ";
}
return " SELECT '".$range_key."' AS `range_key`, COUNT(`id`) AS total
FROM ".TableName::PRODUCT."
WHERE 1 ".$new_price_range;
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Components\Product\AdminController\AProductHotController;
use Hura8\Database\iConnectDB;
use Hura8\System\Config;
class ProductHotModel
{
/* @var $db iConnectDB */
protected $db;
protected $tb_product = "tb_product";
protected $tb_product_hot = "tb_product_hot";
public function __construct() {
$this->db = get_db();
}
public function updateProductHot($pro_id, array $new_types) {
$this->db->runQuery("DELETE FROM " . $this->tb_product_hot . " WHERE `pro_id` = ? ", ['d'], [ $pro_id ]);
$this->db->update(
$this->tb_product,
[
"hot_type" => '',
],
[
'id' => $pro_id,
]
);
$config_hottype = Config::getProductHotTypeList();
//insert what good
$batch_insert = array();
$accepted_types = array();
foreach ($new_types as $hot_type) {
if (!isset($config_hottype[$hot_type])) continue;
$batch_insert[] = [
"pro_id" => $pro_id,
"hot_type" => $hot_type,
];
$accepted_types[] = $hot_type;
}
if (sizeof($batch_insert)) {
$this->db->bulk_insert($this->tb_product_hot, $batch_insert );
$this->db->update(
$this->tb_product,
[
"hot_type" => join(",", $accepted_types),
],
[
"id" => $pro_id,
]
);
}
return true;
}
public function getProductHot(array $product_ids) {
if(!sizeof($product_ids)){
return [];
}
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($product_ids, 'int');
$query = $this->db->runQuery(
"SELECT `pro_id`, `hot_type` FROM ".$this->tb_product_hot." WHERE `pro_id` IN (".$parameterized_ids.") ",
$bind_types,
$product_ids
);
$result = [];
foreach ( $this->db->fetchAll($query) as $rs ) {
$result[$rs['pro_id']][] = $rs['hot_type'];
}
return $result;
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Database\MysqlValue;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;
class ProductImageModel extends aEntityBaseModel
{
protected $product_id = 0;
/* @var ProductModel $objProductModel */
protected $objProductModel;
public function __construct($product_id = 0) {
parent::__construct('product_image');
$this->product_id = $product_id;
$this->objProductModel = new ProductModel();
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
public function setProduct($product_id) {
$this->product_id = $product_id;
}
public function countProductImage($product_id) {
$query = $this->db->runQuery("SELECT COUNT(*) AS total FROM `".$this->tb_entity."` WHERE `pro_id` = ? ", ['d'], [ $product_id]);
if($info = $this->db->fetchAssoc($query)) {
return $info['total'];
}
return 0;
}
protected function _buildQueryOrderBy($sort_by = "new")
{
return " `ordering` DESC, `id` DESC ";
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
/*$condition = array(
"q" => "",
"letter" => "",
"status" => 0,
);*/
$catCondition = [" AND `pro_id` = ? "];
$bind_types = ['d'];
$bind_values = [$this->product_id];
return array( join(" ", $catCondition), $bind_types, $bind_values);
}
protected function getProductMainImage() {
$query = $this->db->runQuery(
"SELECT `id` FROM `".$this->tb_entity."` WHERE `pro_id` = ? AND `is_main` = 1 LIMIT 1",
['d'], [ $this->product_id]
);
return $this->db->fetchAssoc($query);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;
class ProductInfoModel extends aEntityBaseModel
{
protected $richtext_fields = [
'description',
'spec',
'instruction',
];
public function __construct() {
parent::__construct('product_info', '', null, $this->richtext_fields);
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
return null;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\System\Model\EntityLanguageModel;
use Hura8\Interfaces\EntityType;
class ProductLanguageModel extends EntityLanguageModel
{
protected $richtext_fields = [
'description',
'spec',
'instruction',
];
public function __construct() {
parent::__construct(EntityType::PRODUCT, '', $this->richtext_fields);
}
}

View File

@@ -0,0 +1,410 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\iEntityModel;
use Hura8\System\Config;
use Hura8\System\Model\aEntityBaseModel;
use Hura8\Interfaces\EntityType;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
class ProductModel extends aEntityBaseModel implements iEntityModel
{
static $url_module = "product";
static $url_view = "detail";
static $url_type = "product:detail";
protected $tb_product_per_category = 'tb_product_per_category';
protected $tb_collection_product = "tb_collection_product";
protected $tb_product_info = 'tb_product_info';
protected $tb_product_hot = "tb_product_hot";
protected $richtext_fields = [
//'special_offer',
];
public function __construct() {
parent::__construct(
EntityType::PRODUCT,
"",
new ProductSearchModel(),
$this->richtext_fields
);
}
protected function extendedFilterOptions() : array
{
return [
"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,)
"hotType" => array(),// array(saleoff | not | new)
"attribute" => array(), // array(1,2,3,)
"promotion" => "",
"other_filter" => array(), // array(in-stock, has-promotion etc...)
"spec_group_id" => array(), // array(1,2,3,)
];
}
public function getProductInfoBySKU(string $sku) {
$query = $this->db->runQuery(
"SELECT * FROM `".$this->tb_entity."` basic, `".$this->tb_product_info."` info
WHERE basic.`id` = info.`id` AND basic.sku = ?
LIMIT 1 ",
['d'], [$sku]
);
if( $item_info = $this->db->fetchAssoc($query)){
return $item_info;
}
return false;
}
public function getFullInfo($id) {
$query = $this->db->runQuery(
"SELECT * FROM `".$this->tb_entity."` basic, `".$this->tb_product_info."` info
WHERE basic.`id` = info.`id` AND basic.id = ?
LIMIT 1 ",
['d'], [$id]
);
if( $item_info = $this->db->fetchAssoc($query)){
return $item_info;
}
return null;
}
public function getProductCategoryList($pro_id) {
$query = $this->db->runQuery(
"SELECT `category_id` FROM ".$this->tb_product_per_category." WHERE `item_id` = ? ",
['d'], [ $pro_id ]
) ;
$pro_cat = [];
foreach ( $this->db->fetchAll($query) as $rs ) {
$pro_cat[] = $rs['category_id'];
}
return $pro_cat;
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
$where_query = [];
$bind_types = [];
$bind_values = [];
//-------------------
//other filters
if( array_key_exists("other_filter", $filter_condition) && sizeof($filter_condition["other_filter"])) {
foreach ($filter_condition["other_filter"] as $_filter) {
switch ($_filter) {
case "in-stock";
$where_query[] = " AND quantity > 0 ";
break;
case "has-vat";
$where_query[] = " AND `has_vat` = 1 ";
break;
case "out-stock";
$where_query[] = " AND `quantity` = 0 ";
break;
case "has-market-price";
$where_query[] = " AND `market_price` > 0 ";
break;
case "no-price";
$where_query[] = " AND `price` = 0 ";
break;
case "no-warranty";
$where_query[] = " AND LENGTH(`warranty`) < 2 ";
break;
case "no-sku";
$where_query[] = " AND LENGTH(`sku`) < 2 ";
break;
case "has-config";
$where_query[] = " AND `config_count` > 0 ";
break;
case "no-image";
$where_query[] = " AND `image_count` = 0 ";
break;
case "no-category";
$where_query[] = " AND `category` = '0' ";
break;
case "display-off";
$where_query[] = " AND `status`=0 ";
break;
case "display-on";
$where_query[] = " AND `status`=1 ";
break;
case "has-promotion":
$where_query[] = " AND LENGTH(`special_offer`) < 5 ";
break;
//...add more
}
}
}
//- brand id or ids or brand_indexes
if( array_key_exists("brand", $filter_condition) && sizeof($filter_condition["brand"])) {
$condition = array();
foreach ($filter_condition["brand"] as $brand_id) {
if(!intval($brand_id)) continue;
$condition[] = " brand_id = ? ";
$bind_types[] = 'd';
$bind_values[] = $brand_id;
}
if(sizeof($condition)) {
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
}
}
//- collection id or ids
if( array_key_exists("collection", $filter_condition) && sizeof($filter_condition["collection"])) {
$condition = array();
foreach ($filter_condition["collection"] as $_id) {
if(!intval($_id)) continue;
$condition[] = " `id` IN ( SELECT `product_id` FROM ".$this->tb_collection_product." WHERE `collection_id` = ? ) ";
$bind_types[] = 'd';
$bind_values[] = $_id;
}
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
}
//- rating: 1-> 5
if( array_key_exists("rating", $filter_condition) && sizeof($filter_condition["rating"])) {
$condition = array();
foreach ($filter_condition["rating"] as $_id) {
$condition[] = " `rating` = ? ";
$bind_types[] = 'd';
$bind_values[] = $_id;
}
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
}
//- category id or ids
if( array_key_exists("category", $filter_condition) && sizeof($filter_condition["category"])) {
$objProductCategoryModel = new ProductCategoryModel();
$condition = array();
foreach ($filter_condition["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` = ? ";
$bind_types[] = 'd';
$bind_values[] = $cat_id;
}
}
if(sizeof($condition)) {
$where_query[] = " AND `id` IN ( SELECT DISTINCT `item_id` FROM ".$this->tb_product_per_category." WHERE " . join(" OR ", $condition) . " )";
}
}
// spec_group_id
if( array_key_exists("spec_group_id", $filter_condition) && sizeof($filter_condition["spec_group_id"])) {
$condition = array();
foreach ($filter_condition["spec_group_id"] as $_id) {
if(!$_id) continue;
$condition[] = " `spec_group_id` = ? ";
$bind_types[] = 'd';
$bind_values[] = $_id;
}
$where_query[] = " AND ( ".join(" OR ", $condition )." ) ";
}
//- hotType: saleoff | not | new | or combination of types
if( array_key_exists("hotType", $filter_condition) && sizeof($filter_condition["hotType"])) {
$config_hottype = Config::getProductHotTypeList();
$condition = array();
foreach ($filter_condition["hotType"] as $_id) {
if(!array_key_exists($_id, $config_hottype)) continue;
$condition[] = " `hot_type` = ? ";
$bind_types[] = 's';
$bind_values[] = $_id;
}
if(sizeof($condition)) {
$where_query[] = " AND `id` IN (SELECT `pro_id` FROM ".$this->tb_product_hot." WHERE 1 AND ( ".join(" OR ", $condition)." ) ) ";
}
}
//- attribute values
/*
if( array_key_exists("attribute", $filter_condition) && sizeof($filter_condition["attribute"])) {
$filter_attr_value_list = $filter_condition["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($filter_condition["attribute"], $value_id))] ),
];
}
}
*/
//- attribute values
if( array_key_exists("attribute", $filter_condition) && sizeof($filter_condition["attribute"])) {
$filter_attr_value_list = $filter_condition["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 ";
}
//- price range
if(
isset($filter_condition["price"])
&& sizeof($filter_condition["price"])
&& ($filter_condition["price"]['min'] > 0 || $filter_condition["price"]['max'] > 0)
) {
//limit by price range
$maxPrice = DataClean::makeInputSafe($filter_condition["price"]['max'], DataType::INTEGER);
$minPrice = DataClean::makeInputSafe($filter_condition["price"]['min'], DataType::INTEGER);
$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."' ";
}
$where_query[] = " AND ". $price_range_query;
}
// ------------
return array( join(" ", $where_query), $bind_types, $bind_values);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\iSearch;
use Hura8\System\Model\aSearchBaseModel;
class ProductSearchModel extends aSearchBaseModel implements iSearch
{
private $filter_fields = [
"price" => "tb_product.price",
"ranking" => "tb_product.ranking",
"status" => "tb_product.status",
"brand" => "tb_product.brand_id",
];
private $fulltext_fields = [
"category_keywords" => ["tb_product_category.title", ],
"product_keywords" => ["tb_product.sku", "tb_product.title", "tb_product.model", "tb_product.related_keywords"],
];
public function __construct()
{
parent::__construct(
"tb_product",
$this->fulltext_fields,
$this->filter_fields
);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;
class ProductSpecGroupAttributeModel extends aEntityBaseModel
{
protected $tb_product = 'tb_product';
protected $tb_product_spec = 'tb_product_spec';
protected $tb_product_spec_group = 'tb_product_spec_group';
protected $tb_product_spec_group_record = 'tb_product_spec_group_record';
public function __construct() {
parent::__construct('product_spec_group_record');
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
public function getSpecGroupAttribute($group_id)
{
$query = $this->db->runQuery(
"SELECT * FROM `".$this->tb_product_spec_group_record."` WHERE `group_id` = ? ORDER BY `ordering` ASC ",
['d'], [$group_id]
);
return $this->db->fetchAll($query);
}
protected function updateGroupAttributeCount($group_id) {
$this->db->runQuery("UPDATE `".$this->tb_product_spec_group."` SET
`attribute_count` = (SELECT COUNT(*) FROM `".$this->tb_product_spec_group_record."` WHERE `group_id` = ? )
WHERE `id` = ? LIMIT 1 ", ['d', 'd' ], [ $group_id, $group_id ]);
}
protected function buildQueryCondition(array $condition)
{
// TODO: Implement buildQueryCondition() method.
}
protected function buildOrderByCondition($order_by)
{
// TODO: Implement buildOrderByCondition() method.
}
protected function _buildQueryConditionExtend(array $extend_filter_conditions) : ?array
{
return null;
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;
class ProductSpecGroupModel extends aEntityBaseModel
{
protected $tb_product = 'tb_product';
protected $tb_product_spec_group = 'tb_product_spec_group';
protected $tb_product_attribute = 'tb_product_attribute';
public function __construct() {
parent::__construct('product_spec_group');
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
public function getSpecGroupAttribute($group_id) {
$objProductSpecGroupAttributeModel = new ProductSpecGroupAttributeModel();
return $objProductSpecGroupAttributeModel->getSpecGroupAttribute($group_id);
}
protected function clearProductAttributes($product_id) {
$this->db->runQuery(
"DELETE FROM `".$this->tb_product_attribute."` WHERE `pro_id` = ? ",
[ 'd' ], [ $product_id ]
);
}
public function clearProductSpecGroup($product_id) {
$this->clearProductAttributes($product_id);
$product_spec_group_id = $this->getProductSpecGroupId($product_id);
// update
$this->db->runQuery(
"UPDATE `".$this->tb_product."` SET
`spec_group_id` = 0
WHERE `id` = ? LIMIT 1 ",
[ 'd' ], [ $product_id ]
);
$this->updateSpecGroupProductCount($product_spec_group_id);
return true;
}
public function setProductSpecGroup($product_id, $new_group_id)
{
$current_group_id = $this->getProductSpecGroupId($product_id);
if($current_group_id != $new_group_id) {
// update
$this->db->runQuery(
"UPDATE `".$this->tb_product."` SET
`spec_group_id` = ?
WHERE `id` = ? LIMIT 1 ",
[ 'd', 'd' ], [ $new_group_id, $product_id ]
);
$this->updateSpecGroupProductCount($new_group_id);
$this->clearProductAttributes($product_id);
return true;
}
return false;
}
protected function updateSpecGroupProductCount($group_id) {
$this->db->runQuery(
"UPDATE `".$this->tb_product_spec_group."` SET
`product_count` = (SELECT COUNT(*) FROM ".$this->tb_product." WHERE `spec_group_id` = ? )
WHERE `id` = ? LIMIT 1 ",
[ 'd', 'd' ], [ $group_id, $group_id ]
);
}
public function getProductSpecGroupInfo($product_id)
{
$product_spec_group_id = $this->getProductSpecGroupId($product_id);
return ($product_spec_group_id) ? $this->getSpecGroupInfo($product_spec_group_id) : false ;
}
public function getProductSpecGroupId($product_id)
{
$query = $this->db->runQuery("SELECT `spec_group_id` FROM `".$this->tb_product."` WHERE `id` = ? LIMIT 1 ", ['d'], [$product_id]);
if ($info = $this->db->fetchAssoc($query) ) {
return $info['spec_group_id'] ;
}
return 0;
}
public function getSpecGroupInfo($group_id)
{
$query = $this->db->runQuery("SELECT * FROM `".$this->tb_product_spec_group."` WHERE `id` = ? ", ['d'], [$group_id]);
return $this->db->fetchAssoc($query);
}
protected function buildQueryCondition(array $condition)
{
$catCondition = [];
//Tim kiem theo tu khoa
if(isset($condition["q"]) && $condition["q"]){
$catCondition[] = " AND `title` LIKE '%".$this->db->escape($condition["q"])."%' ";
}
return join(" ", $catCondition);
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
$where_condition = "";
$bind_types = [];
$bind_values = [];
return [
$where_condition,
$bind_types,
$bind_values
];
}
}

View File

@@ -0,0 +1,181 @@
<?php
namespace Hura8\Components\Product\Model;
use Hura8\Components\Product\Controller\ProductController;
use Hura8\Interfaces\AppResponse;
use Hura8\System\Model\aEntityBaseModel;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
class ProductVariantModel extends aEntityBaseModel
{
protected $product_id = 0;
protected $tb_product = "tb_product";
protected $tb_variant_option_sample = "tb_product_variant_option_sample";
public function __construct($product_id) {
parent::__construct('product_variant');
$this->product_id = $product_id;
}
protected function extendedFilterOptions() : array
{
return [
// empty for now
];
}
public function getProductVariantOption($product_id){
$query = $this->db->runQuery("SELECT `variant_option` FROM `".$this->tb_product."` WHERE `id` = ? LIMIT 1", ['d'], [ $product_id ]) ;
if($rs = $this->db->fetchAssoc($query)) {
return ($rs['variant_option']) ? \json_decode($rs['variant_option'], true) : null;
}
return null;
}
//use a product's variant-option to create a sample, so next product can select without recreate from beginning
public function createVariantOptionSample($use_from_pro_id, $sample_title) {
if( !$use_from_pro_id || strlen($sample_title) < 3 ) return false;
$pro_variant_option = $this->getProductVariantOption($use_from_pro_id);
if(!$pro_variant_option) {
return false;
}
$pro_variant_option_index = md5(\json_encode($pro_variant_option));
$check_duplicate = $this->db->runQuery(
"SELECT `id` FROM ".$this->tb_variant_option_sample." WHERE `variant_option_index` = ? LIMIT 1 ",
['s'], [ $pro_variant_option_index ]
);
if($this->db->fetchAssoc($check_duplicate)) {
return false;
}
// ok to save
$this->db->insert(
$this->tb_variant_option_sample,
[
"title" => $sample_title,
"variant_option" => \json_encode($pro_variant_option),
"variant_option_index" => $pro_variant_option_index,
"create_time" => CURRENT_TIME,
]
);
return true;
}
public function getVariantOptionSample() {
$query = $this->db->runQuery("SELECT * FROM ".$this->tb_variant_option_sample." ORDER BY `id` DESC LIMIT 500 ");
return $this->db->fetchAll($query);
}
public function getProductVariantPriceRange(){
$result = [
"sale_price" => [
"min" => 0,
"max" => 0,
],
"market_price" => [
"min" => 0,
"max" => 0,
],
];
$query = $this->db->runQuery(
" SELECT `sale_price`, `market_price`, `extend` FROM `".$this->tb_entity."` WHERE `product_id` = ? ",
['d'], [$this->product_id]
);
foreach ( $this->db->fetchAll($query) as $info) {
// find min
if($info["sale_price"] > 0 && ( $info["sale_price"] < $result["sale_price"]["min"] || $result["sale_price"]["min"] == 0 ) ) {
$result["sale_price"]["min"] = $info["sale_price"];
}
// find max
if($info["sale_price"] > 0 && $info["sale_price"] > $result["sale_price"]["max"] ) {
$result["sale_price"]["max"] = $info["sale_price"];
}
// market_price
$market_price = $info["market_price"];
if($info['extend']) {
$extend = unserialize($info['extend']);
if(isset($extend['market_price'])) $market_price = clean_price($extend['market_price'], "vnd");
}
if($market_price > 0 && ( $market_price < $result["market_price"]["min"] || $result["market_price"]["min"] == 0 ) ) {
$result["market_price"]["min"] = $market_price;
}
if($market_price > 0 && $market_price > $result["market_price"]["max"] ) {
$result["market_price"]["max"] = $market_price;
}
}
return $result;
}
protected function _buildQueryConditionExtend(array $filter_condition) : ?array
{
$where_condition = " AND `product_id` = ? ";
$bind_types = ["d"];
$bind_values = [$this->product_id];
return [
$where_condition,
$bind_types,
$bind_values
];
}
protected function _buildQueryOrderBy($sort_by = "new")
{
return " `ordering` DESC, `id` DESC ";
}
protected function formatItemInList(array $item_info): array
{
$info = $item_info;
if($item_info['attribute']) $info['attribute'] = \json_decode($item_info['attribute'], true);
return $info;
}
protected function updateProductVariantCount() {
$this->db->runQuery(
"UPDATE ".$this->tb_product." SET
`config_count` = ( SELECT COUNT(*) AS total FROM `".$this->tb_entity."` WHERE `product_id` = ? AND `status` = 1 )
WHERE `id` = ? ",
['d', 'd'], [ $this->product_id, $this->product_id]
) ;
}
protected function formatItemInfo(array $item_info) : ?array
{
$info = $item_info;
if($info['attribute']) $info['attribute'] = \json_decode($info['attribute'], true);
return $info;
}
}