c
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\System\Controller\aAdminEntityBaseController;
|
||||
use Hura8\Components\Product\Model\ProductAttributeLanguageModel;
|
||||
use Hura8\Components\Product\Model\ProductAttributeModel;
|
||||
use Hura8\Components\Product\Model\ProductAttributeValueModel;
|
||||
use Hura8\System\Security\DataClean;
|
||||
use Hura8\System\Security\DataType;
|
||||
|
||||
|
||||
class AProductAttributeController extends aAdminEntityBaseController
|
||||
{
|
||||
/* @var ProductAttributeModel $objProductAttributeModel */
|
||||
protected $objProductAttributeModel;
|
||||
|
||||
/* @var ProductAttributeLanguageModel $objProductAttributeLanguageModel */
|
||||
protected $objProductAttributeLanguageModel;
|
||||
|
||||
protected $view_language = LANGUAGE;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->objProductAttributeModel = new ProductAttributeModel();
|
||||
|
||||
if(!$this->isDefaultLanguage()) {
|
||||
$this->objProductAttributeLanguageModel = new ProductAttributeLanguageModel($this->view_language);
|
||||
//$this->objProductAttributeLanguageModel->createTableLang();
|
||||
|
||||
parent::__construct($this->objProductAttributeModel, $this->objProductAttributeLanguageModel);
|
||||
|
||||
}else{
|
||||
parent::__construct($this->objProductAttributeModel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getProductAttributes($product_id) {
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel(0);
|
||||
|
||||
$result = [];
|
||||
foreach ($objProductAttributeValueModel->getProductAttributes($product_id) as $info) {
|
||||
$result[$info['attr_id']][] = $info['attr_value_id'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function updateProductAttributes($product_id, array $current_value, array $new_value) {
|
||||
/*
|
||||
$current_value => Array
|
||||
(
|
||||
// attribute_id => [value1, value2]
|
||||
[2] => Array
|
||||
(
|
||||
[0] => 2
|
||||
[1] => 3
|
||||
)
|
||||
|
||||
[1] => Array
|
||||
(
|
||||
[0] => 1
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
$new_value => Array
|
||||
(
|
||||
// attribute_id => new_str_values by lines
|
||||
[2] => asdas
|
||||
[1] => asda
|
||||
)
|
||||
* */
|
||||
|
||||
// list of values for product
|
||||
$product_value_ids = [];
|
||||
|
||||
// use current values
|
||||
foreach ($current_value as $_attr_id => $_value_ids) {
|
||||
$product_value_ids = array_merge($product_value_ids, $_value_ids);
|
||||
}
|
||||
|
||||
// create new values for attributes
|
||||
foreach ($new_value as $_attr_id => $_value_text) {
|
||||
$new_value_texts = array_filter(explode("\n", $_value_text));
|
||||
foreach ($new_value_texts as $new_value) {
|
||||
// if exist
|
||||
$check_exist = $this->getValueByTitle($_attr_id, $new_value);
|
||||
if($check_exist) {
|
||||
$product_value_ids[] = $check_exist['id'];
|
||||
}else{
|
||||
$try_create_id = $this->addValue($_attr_id, ['title' => $new_value]);
|
||||
if($try_create_id) $product_value_ids[] = $try_create_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel(0);
|
||||
|
||||
return $objProductAttributeValueModel->updateProductAttributes($product_id, $product_value_ids);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function updateAttributeInSpecGroup($group_id, $attr_id, array $info) {
|
||||
$this->objProductAttributeModel->updateAttributeInSpecGroup($group_id, $attr_id, $info);
|
||||
}
|
||||
|
||||
public function removeAttributeFromSpecGroup($group_id, $attr_id) {
|
||||
$this->objProductAttributeModel->removeAttributeFromSpecGroup($group_id, $attr_id);
|
||||
}
|
||||
|
||||
public function addAttributeToSpecGroup($group_id, $attr_id, $ordering) {
|
||||
$this->objProductAttributeModel->addAttributeToSpecGroup($group_id, $attr_id, $ordering);
|
||||
}
|
||||
|
||||
public function updateAttributeInCategory($cat_id, $attr_id, array $info) {
|
||||
$this->objProductAttributeModel->updateAttributeInCategory($cat_id, $attr_id, $info);
|
||||
}
|
||||
|
||||
public function removeAttributeFromCategory($cat_id, $attr_id) {
|
||||
$this->objProductAttributeModel->removeAttributeFromCategory($cat_id, $attr_id);
|
||||
}
|
||||
|
||||
public function addAttributeToCategory($cat_id, $attr_id, $ordering) {
|
||||
$this->objProductAttributeModel->addAttributeToCategory($cat_id, $attr_id, $ordering);
|
||||
}
|
||||
|
||||
public function getAllAtributes() {
|
||||
return $this->objProductAttributeModel->getList(["numPerPage" => 2000]);
|
||||
}
|
||||
|
||||
public function deleteValue($attr_id, $value_id) {
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel($attr_id);
|
||||
return $objProductAttributeValueModel->delete($value_id);
|
||||
}
|
||||
|
||||
public function updateValue($attr_id, $value_id, array $info) {
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel($attr_id);
|
||||
return $objProductAttributeValueModel->updateFields($value_id, $info);
|
||||
}
|
||||
|
||||
public function getValueByTitle($attr_id, $value_title) {
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel($attr_id);
|
||||
$filter_code = DataClean::makeInputSafe($value_title, DataType::ID);
|
||||
return $objProductAttributeValueModel->getInfoByCode($filter_code);
|
||||
}
|
||||
|
||||
public function addValue($attr_id, array $info) {
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel($attr_id);
|
||||
return $objProductAttributeValueModel->create($info);
|
||||
}
|
||||
|
||||
public function getListAttributeValues($attr_id) {
|
||||
$objProductAttributeValueModel = new ProductAttributeValueModel($attr_id);
|
||||
return $objProductAttributeValueModel->getList(['numPerPage' => 200]);
|
||||
}
|
||||
|
||||
protected function deleteFileBeforeDeleteItem($item_id): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Controller\bProductCategoryController;
|
||||
use Hura8\Interfaces\AppResponse;
|
||||
use Hura8\Components\Product\Model\ProductCategoryInfoModel;
|
||||
use Hura8\Interfaces\iEntityAdminCategoryController;
|
||||
use Hura8\Traits\AdminEntityCategoryControllerTraits;
|
||||
|
||||
|
||||
class AProductCategoryController extends bProductCategoryController implements iEntityAdminCategoryController
|
||||
{
|
||||
|
||||
use AdminEntityCategoryControllerTraits;
|
||||
|
||||
|
||||
public function updateItemCount($id) {
|
||||
$this->objProductCategoryModel->updateItemCount($id);
|
||||
}
|
||||
|
||||
|
||||
public function getAttributeList($catId) {
|
||||
return $this->objProductCategoryModel->getAttributeList($catId);
|
||||
}
|
||||
|
||||
|
||||
public function create(array $info) : AppResponse
|
||||
{
|
||||
$res = parent::create($info);
|
||||
|
||||
if($res->getStatus() == 'ok') {
|
||||
$objProductCategoryInfoModel = new ProductCategoryInfoModel();
|
||||
$objProductCategoryInfoModel->createInfo($res->getData(), $info);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public function update($id, array $info) : AppResponse
|
||||
{
|
||||
if(!$this->isDefaultLanguage()) {
|
||||
return parent::update($id, $info);
|
||||
}
|
||||
|
||||
// update info
|
||||
$objProductCategoryInfoModel = new ProductCategoryInfoModel();
|
||||
$objProductCategoryInfoModel->updateInfo($id, $info);
|
||||
|
||||
return parent::update($id, $info);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Controller\bProductCollectionController;
|
||||
use Hura8\Interfaces\iEntityAdminCategoryController;
|
||||
use Hura8\Traits\AdminEntityCategoryControllerTraits;
|
||||
|
||||
|
||||
class AProductCollectionController extends bProductCollectionController implements iEntityAdminCategoryController
|
||||
{
|
||||
|
||||
use AdminEntityCategoryControllerTraits;
|
||||
|
||||
public function updateProduct($product_id, $collection_id, array $info)
|
||||
{
|
||||
return $this->objProductCollectionModel->updateProduct($product_id, $collection_id, $info);
|
||||
}
|
||||
|
||||
|
||||
public function removeProduct($product_id, $collection_id)
|
||||
{
|
||||
return $this->objProductCollectionModel->removeProduct($product_id, $collection_id);
|
||||
}
|
||||
|
||||
|
||||
public function addProduct($product_id, $collection_id, $ordering=0)
|
||||
{
|
||||
return $this->objProductCollectionModel->addProduct($product_id, $collection_id, $ordering);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Controller\bProductController;
|
||||
use Hura8\Components\Product\Model\ProductImageModel;
|
||||
use Hura8\Components\Product\Model\ProductInfoModel;
|
||||
|
||||
// Main class extend from base class implementing an interface
|
||||
// Main class use traits shared by other classes with same responsibilities
|
||||
|
||||
class AProductController extends bProductController {
|
||||
|
||||
|
||||
protected function extendFilterConditions(): 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" => "",
|
||||
"storeId" => array(), // array(1,2,3,)
|
||||
"other_filter" => array(), // array(in-stock, has-promotion etc...)
|
||||
"spec_group_id" => array(), // array(1,2,3,)
|
||||
];
|
||||
}
|
||||
|
||||
//get product image list
|
||||
public function productImageList($proId){
|
||||
$objProductImageModel = new ProductImageModel($proId);
|
||||
$result = array();
|
||||
foreach ( $objProductImageModel->getList(["numPerPage" => 100]) as $rs ) {
|
||||
|
||||
$rs['image'] = static::getResizedImageCollection($rs['img_name']);
|
||||
|
||||
$result[] = $rs;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// get only from tb_product_info
|
||||
public function getInfoMore($id)
|
||||
{
|
||||
$objProductInfoModel = new ProductInfoModel();
|
||||
$info = $objProductInfoModel->getInfo($id);
|
||||
|
||||
if(!$this->isDefaultLanguage() && $info) {
|
||||
$language_info = $this->iEntityLanguageModel->getInfo($id);
|
||||
$final_info = [];
|
||||
foreach ($info as $_k => $_v) {
|
||||
$final_info[$_k] = $language_info[$_k] ?? $_v;
|
||||
}
|
||||
|
||||
return $final_info;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function getInfoMoreEmpty($addition_field_value = [])
|
||||
{
|
||||
$objProductInfoModel = new ProductInfoModel();
|
||||
return $objProductInfoModel->getEmptyInfo($addition_field_value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\System\Url;
|
||||
use Hura8\Components\Product\Controller\ProductFilterController;
|
||||
|
||||
|
||||
class AProductFilterController extends ProductFilterController
|
||||
{
|
||||
|
||||
|
||||
public static function getSortOptions($order) {
|
||||
return array(
|
||||
array(
|
||||
"selected" => '',
|
||||
"name" => "Sắp xếp sản phẩm",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("order"=>"")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($order == 'ordering') ? "selected" : "",
|
||||
"name" => "Thứ tự cửa hàng",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("order"=>"ordering")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($order == 'view') ? "selected" : "",
|
||||
"name" => "Xem nhiều nhất",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("order"=>"view")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($order == 'new') ? "selected" : "",
|
||||
"name" => "Mới nhất",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("order"=>"new")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($order == 'last-update') ? "selected" : "",
|
||||
"name" => "Thời gian cập nhật",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("order"=>"last-update")),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function getFilterOptions($other_filter) {
|
||||
|
||||
return array(
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-price') ? "selected" : "",
|
||||
"name" => "Giá bán = 0",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-price")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'in-stock') ? "selected" : "",
|
||||
"name" => "Còn hàng",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"in-stock")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'out-stock') ? "selected" : "",
|
||||
"name" => "Hết hàng",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"out-stock")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'has-market-price') ? "selected" : "",
|
||||
"name" => "Có giá thị trường",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"has-market-price")),
|
||||
),
|
||||
|
||||
array(
|
||||
"selected" => ($other_filter == 'has-promotion') ? "selected" : "",
|
||||
"name" => "Có khuyến mại",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"has-promotion")),
|
||||
),
|
||||
|
||||
array(
|
||||
"selected" => ($other_filter == 'has-config') ? "selected" : "",
|
||||
"name" => "Có cấu hình",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"has-config")),
|
||||
),
|
||||
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-sku') ? "selected" : "",
|
||||
"name" => "Chưa có mã kho",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-sku")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-image') ? "selected" : "",
|
||||
"name" => "Chưa có ảnh",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-image")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'display-off') ? "selected" : "",
|
||||
"name" => "Chưa hiển thị",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"display-off")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'display-on') ? "selected" : "",
|
||||
"name" => "Đang hiển thị",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"display-on")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-category') ? "selected" : "",
|
||||
"name" => "Chưa có danh mục",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-category")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-brand') ? "selected" : "",
|
||||
"name" => "Chưa có thương hiệu",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-brand")),
|
||||
),
|
||||
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-warranty') ? "selected" : "",
|
||||
"name" => "Chưa có bảo hành",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-warranty")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-description') ? "selected" : "",
|
||||
"name" => "Chưa có mô tả",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-description")),
|
||||
),
|
||||
array(
|
||||
"selected" => ($other_filter == 'no-spec-text') ? "selected" : "",
|
||||
"name" => "Chưa có thông số nhập text",
|
||||
"url" => Url::buildUrl(CURRENT_URL, array("other_filter"=>"no-spec-text")),
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,948 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
|
||||
use Hura8\System\ProductFilterPrice;
|
||||
use Hura8\System\Registry;
|
||||
use Hura8\System\Security;
|
||||
use Hura8\System\Url;
|
||||
use Hura8\Components\Brand\Model\BrandModel;
|
||||
use Hura8\Components\Product\Model\ProductAttributeModel;
|
||||
use Hura8\Components\Product\Model\ProductCategoryModel;
|
||||
use Hura8\Components\Product\Model\ProductSearchModel;
|
||||
use Hura8\System\Security\DataType;
|
||||
use Hura8\Interfaces\TableName;
|
||||
|
||||
class AProductFilterOldController
|
||||
{
|
||||
|
||||
protected $filters = [
|
||||
"price" => false,
|
||||
"brand" => array(),
|
||||
"collection" => array(),
|
||||
"supplier" => array(),
|
||||
"rating" => array(),
|
||||
"category" => array(),
|
||||
"status" => "",
|
||||
"query" => "",
|
||||
"hotType" => "",//saleoff | not | new
|
||||
"attribute" => [],//,3793,3794,
|
||||
"ids" => array(),
|
||||
'excluded_ids' => array(),
|
||||
"promotion" => "",
|
||||
"storeId" => '',
|
||||
"other_filter" => array() //in-stock, has-promotion etc...
|
||||
];
|
||||
|
||||
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getDefaultFilter() {
|
||||
return [
|
||||
"price" => self::getPriceFilterRange(),
|
||||
"brand" => $this->getBrandFilter(),
|
||||
"collection" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('collection'))),
|
||||
"supplier" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('supplier'))),
|
||||
"rating" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('rating'))),
|
||||
"category" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('category'))),
|
||||
//"status" => "1",
|
||||
"query" => getRequest('q', ''),
|
||||
"hotType" => getRequest('hotType'),//saleoff | not | new
|
||||
"attribute" => $this->getAttributeFilter([]),//,3793,3794,
|
||||
"promotion" => getRequest('promo', ''),
|
||||
"ids" => array_filter(explode(',', str_replace(" ", "", getRequest('ids', '')))),
|
||||
'excluded_ids' => [],
|
||||
"storeId" => getRequest('storeId', ''),
|
||||
"other_filter" => array_filter(explode(",", getRequest('other_filter', ''))), //in-stock, has-promotion etc...
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// build the user filters for product query
|
||||
// we can modify the code to accept various types of url customization
|
||||
public function getUserFilter(array $category_list_id) {
|
||||
return [
|
||||
"price" => self::getPriceFilterRange(),
|
||||
"brand" => $this->getBrandFilter(),
|
||||
"collection" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('collection'))),
|
||||
"supplier" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('supplier'))),
|
||||
"rating" => array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('rating'))),
|
||||
"category" => $category_list_id,
|
||||
//"status" => "1",
|
||||
"query" => getRequest('q', ''),
|
||||
"hotType" => getRequest('hotType'),//saleoff | not | new
|
||||
"attribute" => $this->getAttributeFilter( $category_list_id),//,3793,3794,
|
||||
"promotion" => getRequest('promo', ''),
|
||||
"ids" => array_filter(explode(',', str_replace(" ", "", getRequest('ids', '')))),
|
||||
"excluded_ids" => array_filter(explode(',', str_replace(" ", "", getRequest('excluded_ids', '')))),
|
||||
"storeId" => getRequest('storeId', ''),
|
||||
"other_filter" => array_filter(explode(",", getRequest('other_filter', ''))), //in-stock, has-promotion etc...
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// accept url format:
|
||||
// default: ?min=1000&max=20000
|
||||
// custom: ?p=15trieu-20-trieu
|
||||
public static function getPriceFilterRange(){
|
||||
// default format
|
||||
if(!defined('PRICE_FILTER_FORMAT') || PRICE_FILTER_FORMAT != 'p') {
|
||||
return array(
|
||||
"min" => getRequestInt("min", 0),
|
||||
"max" => getRequestInt("max", 0),
|
||||
);
|
||||
}
|
||||
|
||||
// custom price range query
|
||||
$price_range_format = getRequest("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 = self::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 = self::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 = self::findPriceUnitMatch($min_part);
|
||||
$max_match = self::findPriceUnitMatch($max_part);
|
||||
|
||||
return [
|
||||
"min" => $min_match['number'] * $unit_translation[$min_match['unit']],
|
||||
"max" => $max_match['number'] * $unit_translation[$max_match['unit']],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
//get a list of products that match filtering conditions
|
||||
public function getProductList(
|
||||
$start_url,
|
||||
$sort_by = "new",
|
||||
$limit = 20,
|
||||
$page = 1
|
||||
) {
|
||||
//list of available filters
|
||||
/*
|
||||
* - price range
|
||||
* - brand id or ids
|
||||
* - collection id or ids
|
||||
* - supplier id
|
||||
* - rating: 1-> 5
|
||||
* - category id or ids
|
||||
* - status: 0|1|null
|
||||
* - detail_page_only: 0 | 1
|
||||
* - query: search keyword
|
||||
* - hotType: saleoff | not | new | or combination of types
|
||||
* - attribute values
|
||||
* ...
|
||||
* */
|
||||
|
||||
/*$filters = array(
|
||||
"price" => array("min"=> 1, "max" => 100),
|
||||
"brand" => array(12,3),
|
||||
"collection" => array(2,3),
|
||||
"supplier" => array(2,3),
|
||||
"rating" => array(2,3),
|
||||
"category" => array(1,2,),
|
||||
"status" => "1",
|
||||
"detail_page_only" => 0,
|
||||
"query" => "",
|
||||
"hotType" => "",//saleoff | not | new
|
||||
"attribute" => "",//,3793,3794,
|
||||
"ids" => array(12,3),
|
||||
'excluded_ids' => array(12,3),
|
||||
"other_filter" => array(in-stock, has-promotion)
|
||||
//...
|
||||
);*/
|
||||
|
||||
$filterPath = [];
|
||||
$filter_messages = [];
|
||||
$where_query = [];
|
||||
$paging_url = $start_url;
|
||||
$filters = $this->cleanFilter();
|
||||
// debug_var($filters);
|
||||
|
||||
//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(isset($filters["other_filter"]) && sizeof($filters["other_filter"])) {
|
||||
foreach ($filters["other_filter"] as $_filter) {
|
||||
switch ($_filter) {
|
||||
case "in-stock";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Còn hàng',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND `quantity` > 0 ";
|
||||
break;
|
||||
case "has-vat";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Có thuế VAT',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND has_vat = 1 ";
|
||||
break;
|
||||
case "out-stock";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Hết hàng',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND quantity = 0 ";
|
||||
break;
|
||||
case "has-market-price";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Có giá thị trường',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND market_price > 0 ";
|
||||
break;
|
||||
case "no-price";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Không có giá',
|
||||
'reset' => Url::buildUrl(CURRENT_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(CURRENT_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(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND LENGTH(`sku`) < 2 ";
|
||||
break;
|
||||
case "has-sku";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Có mã kho hàng',
|
||||
'reset' => Url::buildUrl(CURRENT_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(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND `config_count` > 0 ";
|
||||
break;
|
||||
case "no-image";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Không có ảnh',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
$where_query[] = " AND `image_count` = 0 ";
|
||||
break;
|
||||
case "no-category";
|
||||
$where_query[] = " AND `category_ids` = '' ";
|
||||
break;
|
||||
case "no-brand";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Không có thương hiệu',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['brand' => '']),
|
||||
];
|
||||
|
||||
$where_query[] = " AND `brand_id` = 0 ";
|
||||
break;
|
||||
case "display-off";
|
||||
$where_query[] = " AND `status`=0 ";
|
||||
break;
|
||||
case "display-on";
|
||||
$where_query[] = " AND `status`=1 ";
|
||||
break;
|
||||
case "has-promotion":
|
||||
$filter_messages[] = [
|
||||
'title' => 'Có khuyến mại',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
|
||||
$where_query[] = " AND LENGTH(`special_offer`) > 5 ";
|
||||
break;
|
||||
|
||||
case "no-description";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Không có mô tả',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
|
||||
$where_query["no-description"] = " AND `id` IN ( SELECT `id` FROM ".TableName::PRODUCT_INFO." WHERE LENGTH(`description`) < 5 ) ";
|
||||
break;
|
||||
|
||||
case "no-spec-text";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Không có thông số',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['other_filter' => '']),
|
||||
];
|
||||
|
||||
$where_query["no-spec-text"] = " AND `id` IN ( SELECT `id` FROM ".TableName::PRODUCT_INFO." WHERE LENGTH(`spec`) < 5 ) ";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//- brand id or ids or brand_indexes
|
||||
if(isset($filters["brand"]) && sizeof($filters["brand"])) {
|
||||
global $admin_panel;
|
||||
|
||||
$brand_url_format = (defined('BRAND_FILTER_FORMAT')) ? BRAND_FILTER_FORMAT : '';
|
||||
if(isset($admin_panel) && $admin_panel) $brand_url_format = ''; // custom brand format cannot be used in admin panel
|
||||
|
||||
$objBrandModel = new BrandModel();
|
||||
$condition = array();
|
||||
foreach ($filters["brand"] as $_id) {
|
||||
if(!$_id) continue;
|
||||
|
||||
$brand_info = $objBrandModel->getInfo($_id);
|
||||
if(!$brand_info) continue;
|
||||
|
||||
$filterPath["brand"][] = array(
|
||||
"id" => $brand_info['id'],
|
||||
"name" => $brand_info["title"],
|
||||
);
|
||||
|
||||
$condition[] = " `brand_id` = '".intval($brand_info['id'])."' ";
|
||||
$filter_messages[] = [
|
||||
'title' => $brand_info['title'],
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['brand' => join(FILTER_VALUE_SEPARATOR, remove_item_from_array($filters["brand"], $_id))]),
|
||||
];
|
||||
}
|
||||
|
||||
if(sizeof($condition)) {
|
||||
$paging_url = Url::buildUrl($paging_url, array("brand" => join(FILTER_VALUE_SEPARATOR, $filters['brand'])));
|
||||
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//- collection id or ids
|
||||
if(isset($filters["collection"]) && sizeof($filters["collection"])) {
|
||||
$condition = array();
|
||||
foreach ($filters["collection"] as $_id) {
|
||||
$filterPath["collection"][] = array(
|
||||
"id" => $_id,
|
||||
//"name" => $brand_info["name"],
|
||||
);
|
||||
$condition[] = " `id` IN ( SELECT product_id FROM ".TB_CATEGORY_SPECIAL_PRODUCT." WHERE `special_cat_id`='".intval($_id)."' ) ";
|
||||
$filter_messages[] = [
|
||||
'title' => 'Bộ sưu tập ',
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['collection' => join(',', remove_item_from_array($filters["collection"], $_id))]),
|
||||
];
|
||||
}
|
||||
|
||||
$paging_url = Url::buildUrl($paging_url, array("collection" => join(",", $filters['collection'])));
|
||||
$where_query[] = " AND ( ".join(" OR ", $condition)." )";
|
||||
}
|
||||
|
||||
|
||||
//- category id or ids
|
||||
if(isset($filters["category"]) && sizeof($filters["category"])) {
|
||||
|
||||
$objCategoryProductModel = new ProductCategoryModel();
|
||||
|
||||
$condition = array();
|
||||
|
||||
foreach ($filters["category"] as $cat_id) {
|
||||
$cat_id = intval($cat_id);
|
||||
|
||||
if(!$cat_id) continue;
|
||||
|
||||
$cat_info = $objCategoryProductModel->getInfo($cat_id);
|
||||
|
||||
if($cat_info["is_parent"]) {
|
||||
$childListId = ($cat_info["child_ids"]) ? $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(CURRENT_URL, ['category' => join(',', remove_item_from_array($filters["category"], $cat_id))]),
|
||||
];
|
||||
}
|
||||
|
||||
if(sizeof($condition)) {
|
||||
$paging_url = Url::buildUrl($paging_url, array("category" => join(",", $filters['category'])));
|
||||
$where_query[] = " AND `id` IN ( SELECT DISTINCT `item_id` FROM ".TableName::PRODUCT_PER_CATEGORY." WHERE " . join(" OR ", $condition) . " )";
|
||||
}
|
||||
}
|
||||
|
||||
//- status: 0|1|null
|
||||
if(isset($filters["status"]) && $filters['status']) {
|
||||
$where_query[] = " AND `status` = 1 ";
|
||||
/*$filter_messages[] = [
|
||||
'title' => 'Trạng thái: '.($filters['status'] ? 'Đang hiển thị' : 'Đang ẩn'),
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['status' => '']),
|
||||
];*/
|
||||
}
|
||||
|
||||
|
||||
//- query: search keyword
|
||||
if(isset($filters["query"]) && $filters["query"]) {
|
||||
$keyword_search = $filters["query"];
|
||||
$search_by_product_id = intval(preg_replace('/[^0-9]/i', '', $keyword_search));
|
||||
|
||||
$objProductSearchModel = new ProductSearchModel();
|
||||
|
||||
$match_result = $objProductSearchModel->find($keyword_search);
|
||||
|
||||
$filterPath["search"] = array(
|
||||
"id" => $filters["query"],
|
||||
"name" => $filters["query"],
|
||||
);
|
||||
$filter_messages[] = [
|
||||
'title' => $filters["query"],
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['q' => '']),
|
||||
];
|
||||
|
||||
$paging_url = Url::buildUrl($paging_url, array("q" => $filters["query"]));
|
||||
|
||||
if(sizeof($match_result) > 0) {
|
||||
$where_query[] = " AND ( `id` IN (".join(",", $match_result ).") OR `id` = '".$search_by_product_id."' ) ";
|
||||
}else{
|
||||
$where_query[] = " AND `id` = '".$search_by_product_id."' ";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//- hotType: saleoff | not | new | or combination of types
|
||||
if(isset($filters["hotType"]) && $filters["hotType"]) {
|
||||
$hot_type = preg_replace("/[^a-z0-9_\-]/i","", $filters["hotType"]);
|
||||
$config_hottype = AProductFilterController::getProductHotTypeList();
|
||||
if(isset($config_hottype[$hot_type])) {
|
||||
$filterPath["hotType"] = array(
|
||||
"id" => $filters["hotType"],
|
||||
"name" => $filters["hotType"],
|
||||
);
|
||||
$paging_url = Url::buildUrl($paging_url, array("hotType" => $hot_type));
|
||||
$where_query[] = " AND `id` IN (SELECT `pro_id` FROM ".TB_PRODUCT_HOT." WHERE hot_type = '".$hot_type."' ) ";
|
||||
$filter_messages[] = [
|
||||
'title' => $filters["hotType"],
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['hotType' => '']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
//- attribute values
|
||||
if(isset($filters["attribute"]) && sizeof($filters["attribute"])) {
|
||||
$filter_attr_value_list = $filters["attribute"];
|
||||
//filter = attr_value_1-attr_value_2-attr_value_3,
|
||||
$query_attr_id = [];
|
||||
$count_filter = 0;
|
||||
|
||||
if(ENABLE_FILTER_BY_APIKEY) {
|
||||
//filter = ,api_key_1,api_key_2,api_key_3,
|
||||
foreach($this->translate_api_filter($filter_attr_value_list) as $attr_id){
|
||||
$query_attr_id[] = $attr_id;
|
||||
$count_filter ++;
|
||||
}
|
||||
|
||||
} else {
|
||||
foreach($filter_attr_value_list as $attr_id){
|
||||
$attr_id = (int) $attr_id;
|
||||
if($attr_id) {
|
||||
$query_attr_id[] = $attr_id;
|
||||
$count_filter ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$objProductAttributeModel = new ProductAttributeModel();
|
||||
|
||||
$product_filter_id_match = $objProductAttributeModel->getProductMatchAttributeValue($query_attr_id);
|
||||
|
||||
|
||||
$paging_url = Url::buildUrl($paging_url, array("filter" => join(FILTER_VALUE_SEPARATOR, $filter_attr_value_list)));
|
||||
$where_query[] = (sizeof($product_filter_id_match)) ? " AND `id` IN (".join(', ', $product_filter_id_match).") " : " AND `id` = 0 " ;
|
||||
|
||||
//xay lai url de back
|
||||
foreach($filter_attr_value_list as $value_id ){
|
||||
$att_name = 'att_name'; //$objCategoryProduct->atrValueName($value_id);
|
||||
$filterPath["attribute"][] = array(
|
||||
"id" => $value_id,
|
||||
"name" => $att_name,
|
||||
);
|
||||
$filter_messages[] = [
|
||||
'title' => $att_name,
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['attribute' => join(FILTER_VALUE_SEPARATOR, remove_item_from_array($filters["category"], $value_id))]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
//given products' ids
|
||||
if(isset($filters["ids"]) && is_array($filters["ids"]) && sizeof($filters["ids"])) {
|
||||
$where_query[] = " AND `id` IN (". join(",", $filters["ids"]) .") ";
|
||||
}
|
||||
|
||||
//exclude products' ids
|
||||
if(isset($filters["excluded_ids"]) && is_array($filters["excluded_ids"]) && sizeof($filters["excluded_ids"])) {
|
||||
$where_query[] = " AND `id` NOT IN (". join(",", $filters["excluded_ids"]) .") ";
|
||||
}
|
||||
|
||||
$price_range_query_limit = join(" ",$where_query);
|
||||
|
||||
//- price range
|
||||
if(isset($filters["price"]) && is_array($filters["price"]) && sizeof($filters["price"]) && ($filters["price"]['min'] > 0 || $filters["price"]['max'] > 0)) {
|
||||
//limit by price range
|
||||
$maxPrice = clean_price($filters["price"]['max']);
|
||||
$minPrice = clean_price($filters["price"]['min']);
|
||||
$paging_url = Url::buildUrl($paging_url, array("max"=>$maxPrice, "min"=>$minPrice));
|
||||
|
||||
$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;
|
||||
|
||||
$filterPath["price"] = array(
|
||||
"min" => $minPrice,
|
||||
"max" => $maxPrice,
|
||||
);
|
||||
|
||||
$price_format = ProductFilterPrice::buildPriceRangeFormat($minPrice, $maxPrice);
|
||||
|
||||
$filter_messages[] = [
|
||||
'title' => $price_format['title'],
|
||||
'reset' => Url::buildUrl(CURRENT_URL, ['price' => '']),
|
||||
];
|
||||
}
|
||||
|
||||
// use location price sorting
|
||||
$ordering_clause = $this->getOrderingClause($sort_by, $db_condition, 0);
|
||||
|
||||
$db_condition = join(" ", $where_query);
|
||||
|
||||
$total_number = 0;
|
||||
$list_ids = [];
|
||||
|
||||
/* $query = $this->db->runQuery("SELECT COUNT(`id`) AS total FROM ".TB_PRODUCT_LIGHT." WHERE 1 ".$db_condition." ");
|
||||
if($rs = $this->db->fetchAssoc($query)) {
|
||||
$total_number = $rs['total'];
|
||||
}
|
||||
|
||||
$category_query = " AND idv_product_category.`pro_id` IN (SELECT `id` FROM ".TB_PRODUCT_LIGHT." WHERE 1 ".$db_condition.") ";
|
||||
|
||||
if($location_sorting) {
|
||||
|
||||
$list_ids = array_slice($location_product_ids, ($page-1) * $limit, $limit);
|
||||
|
||||
} else {
|
||||
|
||||
if(in_array($sort_by, ['view', 'name'])) {
|
||||
$query = $this->db->runQuery("
|
||||
SELECT `id`, ".TB_PRODUCT.".proName
|
||||
FROM ".TB_PRODUCT_LIGHT.", ".TB_PRODUCT."
|
||||
WHERE `id` = ".TB_PRODUCT.".`id`
|
||||
".$db_condition."
|
||||
".$ordering_clause."
|
||||
LIMIT ".($page-1) * $limit.", ".$limit."
|
||||
");
|
||||
}else{
|
||||
$query = $this->db->runQuery("
|
||||
SELECT `id` FROM ".TB_PRODUCT_LIGHT."
|
||||
WHERE 1 ".$db_condition."
|
||||
".$ordering_clause."
|
||||
LIMIT ".($page-1) * $limit.", ".$limit."
|
||||
");
|
||||
}
|
||||
|
||||
$list_ids = array_map(function ($rs){
|
||||
return $rs['id'];
|
||||
}, $this->db->fetchAll($query));
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
return [
|
||||
"full_query" => $db_condition,
|
||||
"price_query" => $price_range_query_limit,
|
||||
//"category_query" => $category_query,
|
||||
"filter" => $filterPath,
|
||||
"filter_messages" => $filter_messages,
|
||||
"total" => $total_number,
|
||||
"list_ids" => $list_ids,
|
||||
"url" => $paging_url,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected function cleanFilter() {
|
||||
$clean_filter = [];
|
||||
foreach ($this->filters as $key => $value) {
|
||||
$clean_filter[$key] = $this->clearFilterValue($key, $value);
|
||||
}
|
||||
return $clean_filter;
|
||||
}
|
||||
|
||||
|
||||
protected function clearFilterValue($key, $value) {
|
||||
if($key == 'price') {
|
||||
if(!is_array($value)) return false;
|
||||
$min = isset($value['min']) ? intval($value['min']) : 0;
|
||||
$max = isset($value['max']) ? intval($value['max']) : 0;
|
||||
|
||||
return ['min' => $min, 'max' => $max]; // array("min" => getRequestInt("min", 0), "max" => getRequestInt("max", 0)),
|
||||
}
|
||||
|
||||
if(in_array($key, ['collection', 'supplier', 'rating', 'category', 'ids', 'excluded_ids'])) {
|
||||
return Security::makeListOfInputSafe($value, 'int'); // int1-int2 => array(int1, int2, ...)
|
||||
}
|
||||
|
||||
// accept a-z0-9-
|
||||
if(in_array($key, ['attribute', 'brand'])) {
|
||||
return Security::makeListOfInputSafe($value, 'string');
|
||||
}
|
||||
|
||||
if($key == 'status') {
|
||||
return (in_array($value, [0, 1])) ? $value : 0;
|
||||
}
|
||||
|
||||
if($key == 'query') {
|
||||
return substr(trim(str_replace(['\'', '"'], '', strip_tags($value))), 0, 100); // string
|
||||
}
|
||||
|
||||
if($key == 'hotType') {
|
||||
$config_hottype = AProductFilterController::getProductHotTypeList();
|
||||
return (isset($config_hottype[$value])) ? $value : ''; //saleoff | not | new
|
||||
}
|
||||
|
||||
if($key == 'promotion') {
|
||||
return intval($value);
|
||||
}
|
||||
|
||||
if($key == 'storeId') {
|
||||
return intval($value);
|
||||
}
|
||||
|
||||
if($key == 'detail_page_only') {
|
||||
return intval($value); // 1|0|''
|
||||
}
|
||||
|
||||
if($key == 'other_filter') {
|
||||
return array_filter(
|
||||
array_map(function ($item){
|
||||
return preg_replace('/[^a-z0-9_\.\-\,]/i', '', $item);
|
||||
}, $value )
|
||||
); // array() //in-stock, has-promotion
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
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 getProductIds($price_range_query_limit) {
|
||||
/*$query = $this->db->query("
|
||||
SELECT `id` FROM ".TB_PRODUCT_LIGHT."
|
||||
WHERE 1 ".$price_range_query_limit."
|
||||
LIMIT 10000
|
||||
");
|
||||
|
||||
return array_map(function ($rs){
|
||||
return $rs['id'];
|
||||
}, $this->db->fetchAll($query));*/
|
||||
}
|
||||
|
||||
//10-04-2017 allow ?filter=api_key1,api_key2, ... and translate to id
|
||||
protected function translate_api_filter($filter_api) {
|
||||
/*$filter_attr_value_list = array_filter(explode(",", $filter_api));
|
||||
|
||||
$build_query = array();
|
||||
foreach($filter_attr_value_list as $api_key){
|
||||
$api_key = \preg_replace('/[^a-z0-9\_\-\.]/i', '', $api_key);
|
||||
if($api_key) $build_query[] = " `api_key` = '".$this->db->escape($api_key)."' ";
|
||||
}
|
||||
|
||||
$result = array();
|
||||
if(sizeof($build_query)) {
|
||||
$query = $this->db->runQuery("SELECT id FROM ".TB_ATTRIBUTE_VALUE." WHERE ". join(" OR ", $build_query)) ;
|
||||
foreach ( $this->db->fetchAll($query) as $info ) {
|
||||
$result[] = $info['id'];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;*/
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
// accept url format:
|
||||
// default: ?brand=1
|
||||
// brand_index: ?brand=apple
|
||||
protected function getBrandFilter() {
|
||||
$brand_url_format = (defined('BRAND_FILTER_FORMAT')) ? BRAND_FILTER_FORMAT : '';
|
||||
|
||||
$module = (Registry::getVariable('global')) ? Registry::getVariable('global')['module'] : null;
|
||||
|
||||
if(!$module) {
|
||||
// possible admin panel
|
||||
return array_filter(explode(FILTER_VALUE_SEPARATOR, getRequest('brand', '')));
|
||||
}
|
||||
|
||||
$current_brand_queries = (isset($module['query']['brand'])) ? array_filter(explode(FILTER_VALUE_SEPARATOR, $module['query']['brand'])) : [];
|
||||
|
||||
// fix for brand-detail page
|
||||
// example: domain.com/brand/sony
|
||||
if(isset($module['query']['brandName']) && $module['query']['brandName']) {
|
||||
$objBrandModel = new BrandModel();
|
||||
$brand_info = $objBrandModel->getInfoByUrl($module['query']['brandName']);
|
||||
|
||||
if($brand_url_format == 'brand_index') {
|
||||
$current_brand_queries = array($brand_info['brand_index']);
|
||||
}else{
|
||||
$current_brand_queries = array($brand_info['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if($brand_url_format == 'brand_index') {
|
||||
//i.e ?brand=apple-canon
|
||||
return $current_brand_queries;
|
||||
}
|
||||
|
||||
$selected_brand = $current_brand_queries;
|
||||
if(isset($module['query']['brand_id']) && $module['query']['brand_id']) {
|
||||
$selected_brand[] = intval($module['query']['brand_id']);
|
||||
}
|
||||
|
||||
return $selected_brand;
|
||||
}
|
||||
|
||||
// accept url format:
|
||||
// default: ?filter=3793-3794,
|
||||
// custom: ?ram=8gb&hdd=500GB
|
||||
protected function getAttributeFilter(array $category_list_id){
|
||||
|
||||
$request_filter_list = getRequest('filter', '');
|
||||
|
||||
// custom1
|
||||
if( !$request_filter_list && defined('ATTRIBUTE_FILTER_FORMAT') && ATTRIBUTE_FILTER_FORMAT == 'custom1' ) {
|
||||
// iUCategoryProduct $objCategoryProduct, array $category_list_id
|
||||
return $this->getAttributeFilterPara($category_list_id); //join(FILTER_VALUE_SEPARATOR, $this->getAttributeFilterPara($category_list_id));
|
||||
}
|
||||
|
||||
if(!$request_filter_list) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// default
|
||||
$clean_list = Security::makeListOfInputSafe(
|
||||
explode(FILTER_VALUE_SEPARATOR, str_replace([',', '-', '_'], FILTER_VALUE_SEPARATOR, $request_filter_list) ),
|
||||
DataType::INTEGER
|
||||
) ; //preg_replace("/[^0-9,_\-]/", "", getRequest('filter', ''));//3793-3794,
|
||||
|
||||
return array_filter($clean_list);
|
||||
}
|
||||
|
||||
|
||||
protected function getAttributeFilterPara( array $category_list_id){
|
||||
|
||||
$excluded_keys = ['p', 'min', 'max', 'brand', 'page', 'request_path'];
|
||||
$attr_filter_params = [];
|
||||
|
||||
$query_parameters = Url::parse(CURRENT_URL)['query'];
|
||||
|
||||
|
||||
foreach ( $query_parameters as $key => $value) {
|
||||
if(in_array($key, $excluded_keys) || !$value) continue;
|
||||
|
||||
$attr_filter_params[$key] = $value;
|
||||
}
|
||||
|
||||
|
||||
if(sizeof($attr_filter_params)) {
|
||||
/*$objCategoryProduct = new UCategoryProduct();
|
||||
$category_attributes = $objCategoryProduct->getAttributesForCategory($category_list_id);
|
||||
|
||||
$match_attr_value_ids = [];
|
||||
foreach ($attr_filter_params as $attr_filter_code => $attr_value_api_key) {
|
||||
foreach ($category_attributes as $attribute) {
|
||||
if($attribute['filter_code'] != $attr_filter_code) continue;
|
||||
|
||||
foreach ($attribute['value_list'] as $_value_id => $_value_info) {
|
||||
if($_value_info['info']['api_key'] == $attr_value_api_key) {
|
||||
$match_attr_value_ids[] = $_value_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $match_attr_value_ids;*/
|
||||
return [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
public static 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',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// accept url format:
|
||||
// default: ?min=1000&max=20000
|
||||
// custom: ?p=tu-15-20-trieu
|
||||
protected static function getPriceRange(){
|
||||
// default
|
||||
$min_price = getRequest("min");
|
||||
$max_price = getRequest("max");
|
||||
|
||||
// custom price range query
|
||||
$price_range = getRequest("p"); // duoi-10-trieu , tu-15-20-trieu, tren-30-trieu
|
||||
|
||||
// duoi-10-trieu
|
||||
$match = [];
|
||||
if(preg_match("/^duoi-([0-9]+)-trieu$/i", $price_range, $match)) {
|
||||
$min_price = '';
|
||||
$max_price = $match[1] * 1000000;
|
||||
}
|
||||
elseif (preg_match("/^tu-([0-9]+)-([0-9]+)-trieu$/i", $price_range, $match)) {
|
||||
$min_price = $match[1] * 1000000;
|
||||
$max_price = $match[2] * 1000000;
|
||||
}
|
||||
elseif (preg_match("/^tren-([0-9]+)-trieu$/i", $price_range, $match)) {
|
||||
$min_price = $match[1] * 1000000;
|
||||
$max_price = '';
|
||||
}
|
||||
|
||||
return [
|
||||
"min" => intval($min_price),
|
||||
"max" => intval($max_price),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
protected function getOrderingClause($sort_by, &$where_query, $current_viewed_category = 0) {
|
||||
|
||||
// show by global order
|
||||
$ordering = "ORDER BY ordering DESC, id DESC";
|
||||
|
||||
switch($sort_by) {
|
||||
case "order-new";
|
||||
$ordering = "ORDER BY `ordering` DESC, `id` DESC";
|
||||
break;
|
||||
case "order-last-update";
|
||||
$ordering = "ORDER BY `ordering` DESC, last_update DESC";
|
||||
break;
|
||||
case "last-update";
|
||||
$ordering = "ORDER BY last_update DESC";
|
||||
break;
|
||||
case "order";
|
||||
$ordering = "ORDER BY `ordering` DESC";
|
||||
break;
|
||||
case "new";
|
||||
$ordering = "ORDER BY `id` DESC";
|
||||
break;
|
||||
case "price-asc";
|
||||
$where_query .= " AND `price` > 100 ";
|
||||
$ordering = "ORDER BY `price` ASC";
|
||||
break;
|
||||
case "price-desc";
|
||||
$ordering = " ORDER BY `price` DESC ";
|
||||
break;
|
||||
case "view";
|
||||
$ordering = "ORDER BY `visit` desc";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return $ordering;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Model\ProductHotModel;
|
||||
use Hura8\Traits\ClassCacheTrait;
|
||||
|
||||
class AProductHotController
|
||||
{
|
||||
use ClassCacheTrait;
|
||||
|
||||
/* @var ProductHotModel $objProductHotModel */
|
||||
protected $objProductHotModel;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->objProductHotModel = new ProductHotModel();
|
||||
}
|
||||
|
||||
|
||||
public function getProductHot(array $product_id_array) {
|
||||
$hot_script = $this->objProductHotModel->getProductHot($product_id_array);
|
||||
|
||||
//add empty for other products
|
||||
foreach ($product_id_array as $pro_id) {
|
||||
if(!isset($hot_script[$pro_id])) $hot_script[$pro_id] = [];
|
||||
}
|
||||
|
||||
return $hot_script;
|
||||
}
|
||||
|
||||
|
||||
public function updateProductHot($pro_id, array $new_types) {
|
||||
return $this->objProductHotModel->updateProductHot($pro_id, $new_types);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Model\ProductSpecGroupAttributeModel;
|
||||
use Hura8\System\Controller\aAdminEntityBaseController;
|
||||
|
||||
class AProductSpecGroupAttributeController extends aAdminEntityBaseController
|
||||
{
|
||||
/* @var ProductSpecGroupAttributeModel $objProductSpecGroupAttributeModel */
|
||||
protected $objProductSpecGroupAttributeModel;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->objProductSpecGroupAttributeModel = new ProductSpecGroupAttributeModel();
|
||||
parent::__construct($this->objProductSpecGroupAttributeModel);
|
||||
}
|
||||
|
||||
protected function deleteFileBeforeDeleteItem($item_id): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Model\ProductAttributeModel;
|
||||
use Hura8\Components\Product\Model\ProductSpecGroupModel;
|
||||
use Hura8\System\Controller\aAdminEntityBaseController;
|
||||
|
||||
class AProductSpecGroupController extends aAdminEntityBaseController
|
||||
{
|
||||
/* @var ProductSpecGroupModel $objProductSpecGroupModel */
|
||||
protected $objProductSpecGroupModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->objProductSpecGroupModel = new ProductSpecGroupModel();
|
||||
parent::__construct($this->objProductSpecGroupModel);
|
||||
}
|
||||
|
||||
public function getSpecGroupAttributeWithValues($group_id)
|
||||
{
|
||||
$objProductAttributeModel = new ProductAttributeModel();
|
||||
return $objProductAttributeModel->getSpecGroupAttributeWithValues($group_id);
|
||||
}
|
||||
|
||||
public function getSpecGroupAttribute($group_id)
|
||||
{
|
||||
$objProductAttributeModel = new ProductAttributeModel();
|
||||
return $objProductAttributeModel->getSpecGroupAttribute($group_id);
|
||||
}
|
||||
|
||||
|
||||
public function clearProductSpecGroup($product_id)
|
||||
{
|
||||
return $this->objProductSpecGroupModel->clearProductSpecGroup($product_id);
|
||||
}
|
||||
|
||||
|
||||
public function setProductSpecGroup($product_id, $group_id)
|
||||
{
|
||||
return $this->objProductSpecGroupModel->setProductSpecGroup($product_id, $group_id);
|
||||
}
|
||||
|
||||
|
||||
public function getProductSpec($product_id)
|
||||
{
|
||||
return $this->objProductSpecGroupModel->getProductSpec($product_id);
|
||||
}
|
||||
|
||||
|
||||
public function getProductSpecGroupInfo($product_id)
|
||||
{
|
||||
return $this->objProductSpecGroupModel->getProductSpecGroupInfo($product_id);
|
||||
}
|
||||
|
||||
|
||||
public function getProductSpecGroupId($product_id)
|
||||
{
|
||||
return $this->objProductSpecGroupModel->getProductSpecGroupId($product_id);
|
||||
}
|
||||
|
||||
|
||||
public function getSpecGroupInfo($group_id)
|
||||
{
|
||||
return $this->objProductSpecGroupModel->getSpecGroupInfo($group_id);
|
||||
}
|
||||
|
||||
|
||||
protected function deleteFileBeforeDeleteItem($item_id): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Hura8\Components\Product\AdminController;
|
||||
|
||||
use Hura8\Components\Product\Model\ProductVariantModel;
|
||||
|
||||
class AProductVariantController
|
||||
{
|
||||
/* @var ProductVariantModel $objProductVariantModel */
|
||||
protected $objProductVariantModel;
|
||||
|
||||
|
||||
public function __construct($product_id)
|
||||
{
|
||||
$this->objProductVariantModel = new ProductVariantModel($product_id);
|
||||
}
|
||||
|
||||
|
||||
public function delete($id) {
|
||||
return $this->objProductVariantModel->delete($id);
|
||||
}
|
||||
|
||||
|
||||
public function updateImage($variant_id, $image_name) {
|
||||
return $this->objProductVariantModel->updateFields($variant_id, [
|
||||
"thumbnail" => $image_name
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeImage($variant_id) {
|
||||
return $this->objProductVariantModel->updateFields($variant_id, [
|
||||
"thumbnail" => ''
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function getInfo($id) {
|
||||
return $this->objProductVariantModel->getInfo($id);
|
||||
}
|
||||
|
||||
public function getProductVariantOption($product_id){
|
||||
return $this->objProductVariantModel->getProductVariantOption($product_id);
|
||||
}
|
||||
|
||||
|
||||
//update product's variant options
|
||||
public function updateVariantOption($attribute) {
|
||||
return $this->objProductVariantModel->updateVariantOption($attribute);
|
||||
}
|
||||
|
||||
public function useVariantOptionSample($select_id) {
|
||||
$sample = $this->objProductVariantModel->useVariantOptionSample($select_id);
|
||||
|
||||
return ($sample) ? \json_decode($sample,true) : [];
|
||||
}
|
||||
|
||||
|
||||
//use a product's variant-option to create a choice, so next product can select without recreate from beginning
|
||||
public function createVariantOptionSample($use_from_pro_id, $sample_title) {
|
||||
return $this->objProductVariantModel->createVariantOptionSample($use_from_pro_id, $sample_title);
|
||||
}
|
||||
|
||||
|
||||
public function getVariantOptionSample() {
|
||||
return $this->objProductVariantModel->getVariantOptionSample();
|
||||
}
|
||||
|
||||
public function updateVariant($variant_id, array $variant_info) {
|
||||
if($variant_id) {
|
||||
return $this->objProductVariantModel->update($variant_id, $variant_info);
|
||||
}else{
|
||||
return $this->objProductVariantModel->create($variant_info);
|
||||
}
|
||||
}
|
||||
|
||||
public function getProductVariantPriceRange(){
|
||||
return $this->objProductVariantModel->getProductVariantPriceRange();
|
||||
}
|
||||
|
||||
public function getProductVariantList(){
|
||||
return $this->objProductVariantModel->getList([]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
210
inc/Hura8/Components/Product/Controller/bProductController.php
Normal file
210
inc/Hura8/Components/Product/Controller/bProductController.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
175
inc/Hura8/Components/Product/Model/ProductAttributeModel.php
Normal file
175
inc/Hura8/Components/Product/Model/ProductAttributeModel.php
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
85
inc/Hura8/Components/Product/Model/ProductCategoryModel.php
Normal file
85
inc/Hura8/Components/Product/Model/ProductCategoryModel.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
452
inc/Hura8/Components/Product/Model/ProductFilterModel.php
Normal file
452
inc/Hura8/Components/Product/Model/ProductFilterModel.php
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
95
inc/Hura8/Components/Product/Model/ProductHotModel.php
Normal file
95
inc/Hura8/Components/Product/Model/ProductHotModel.php
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
78
inc/Hura8/Components/Product/Model/ProductImageModel.php
Normal file
78
inc/Hura8/Components/Product/Model/ProductImageModel.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
35
inc/Hura8/Components/Product/Model/ProductInfoModel.php
Normal file
35
inc/Hura8/Components/Product/Model/ProductInfoModel.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
21
inc/Hura8/Components/Product/Model/ProductLanguageModel.php
Normal file
21
inc/Hura8/Components/Product/Model/ProductLanguageModel.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
410
inc/Hura8/Components/Product/Model/ProductModel.php
Normal file
410
inc/Hura8/Components/Product/Model/ProductModel.php
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
33
inc/Hura8/Components/Product/Model/ProductSearchModel.php
Normal file
33
inc/Hura8/Components/Product/Model/ProductSearchModel.php
Normal 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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
151
inc/Hura8/Components/Product/Model/ProductSpecGroupModel.php
Normal file
151
inc/Hura8/Components/Product/Model/ProductSpecGroupModel.php
Normal 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
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
181
inc/Hura8/Components/Product/Model/ProductVariantModel.php
Normal file
181
inc/Hura8/Components/Product/Model/ProductVariantModel.php
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user