<?php
/**
* @Description : This department advances the products process
* @Author : Salar izadi
*/
final class MCE_Products {
public string $table = "mce_products";
public string $table_favorite = "mce_favorites";
public string $table_colors = "mce_colors";
public string $table_downloads = "mce_downloads";
public array $types = [
0 => "Physical",
1 => "Downloadable"
];
/**
* Do not execute this method, this method is automatically executed in the core of MCE
*
* @return void
*/
public function init ( ) {
global $ufo;
$ufo->add_work("mce_pages_get_full_url", function ($page) {
global $ufo;
$product = $this->get($page["id"]);
if (!empty($product["extend"]))
return $ufo->do_work($product["extend"] . "_pages_get_full_url", $page);
return $product["link"];
});
/** Start UFO_Explorer */
$ufo->exert("ufo-explorer-mce", function ($hunted) {
$product = $this->get($hunted->hunted["id"]);
if (!$product) return false;
return array_merge([
"prefix" => [
"slug" => (new MCE_Tables())->meta("slug_product")
]
], $product);
});
$ufo->add_array("ufo-explorer", [
"name" => "mce-products",
"hunter" => function ($explore) use ($ufo) {
$explore->query["where"]["extend"] = $explore->query["where"]["extend"] ?? [
"", "="
];
if (!isset($explore->query["filters"]["category"])) {
$explore->query["filters"]["category"] = !empty(
$explore->query["category"]
) ? $explore->query["category"] : [];
}
return (new MCE_Products())->all($explore->query);
}
]);
$ufo->add_array("ufo-explorer", [
"name" => "single-mce",
"hunter" => function ($explorer) {
return $this->all([
"where" => [
"product" => $explorer->query["id"]
]
]);
},
"reset" => false
]);
/** End UFO_Explorer */
}
/**
* @param int $type
* @return false|string
*/
public function readable_type (int $type) {
return mce_lng($this->types[$type]) ?? false;
}
/**
* @param array|int $page
* @param $limit
* @param int $type
* @param $search
* @param $paging_action
* @param array $where
* @param string $sort
* @param array $filters
* @return array
* @throws Exception
*/
public function all (
$page = 1,
$limit = null,
int $type = -1,
$search = null,
$paging_action = null,
array $where = [],
string $sort = "",
array $filters = []
): array {
global $ufo, $db, $MCE_PRELOAD;
if (is_array($page))
extract($page);
file_put_contents('products.json', json_encode($page, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE))
$pages = new UFO_Pages();
$newList = [];
$tableRows = empty($limit) ? $db->table_rows : $limit;
$db->helper->join("pages p", "p.id=%prefix%" . $this->table . ".product", "LEFT");
if (isset($status))
$db->where("p.status", $status);
if (!empty($search)) $db->helper->where(
"p." . ($search["prop"] ?? "title"),
"%" . ($search["value"] ?? $search) . "%",
"LIKE"
);
if (isset($this->types[$type]))
$where["type"] = $type;
$this->__filters($filters, $search);
$fields = $this->__sort($sort, $search);
foreach ($where as $kw => $vw) {
$where[$db->prefix . $this->table . "." . $kw] = $vw;
unset($where[$kw]);
}
print_r($sort);
$products = $db->pagination($this->table, [
"page" => $page,
"limit" => (int) ($limit ?? $tableRows),
"paging_action" => $paging_action ?? "mce-products-paging"
], $where, array_merge(
/** Limit table columns page */
explode(", ", ltrim(join(
", p.", array_merge(
[""], $MCE_PRELOAD["table_columns_pages"])
), ", ")), ["%prefix%" . $this->table . ".*"],
is_array($fields) ? $fields : []
));
// print_r($products);
foreach ($products["rows"] ?? $products as $item) {
$pageProduct = $pages->get($item["product"]);
if (is_array($pageProduct)) {
unset($pageProduct["id"]);
unset($pageProduct["type"]);
unset($item["id"]);
if (!empty($item["extend"]))
$item[$item["extend"]] = $ufo->do_work("mce-get-product-extend-" . $item["extend"], $item["product"]);
$newList[] = $this->productEditValues($pageProduct + $item);
}
}
$products["rows"] = $newList;
/** Colors */
foreach ($products["rows"] ?? $products as $key => $item) {
if (is_array($item["colors"])) {
foreach ($item["colors"] as $k => $v) {
if ($v["inv"] <= 0)
unset($products["rows"][$key]["colors"][$k]);
}
}
}
return $products;
}
/**
* @param $product
* @return array|false
* @throws Exception
*/
public function get ($product) {
global $ufo, $db;
$page = (new UFO_Pages())->get($product);
if ($page) {
$row = $db->get($this->table, "product", $page["id"]);
if (isset($row[0])) {
$row = $row[0];
unset($row["id"]);
unset($page["id"]);
unset($page["type"]);
$row = $this->productEditValues(array_merge($row, $page));
$row["old_link"] = $page["link"];
$colors = [];
foreach (is_array($row["colors"]) ? $row["colors"] : [] as $color) {
$get = $this->get_color($color["id"]);
if ($get) {
unset($color["id"]);
$colors[] = array_merge($get, $color);
}
}
$row["colors"] = $colors;
if ($ufo->isset_key($row["more"], "transport")) {
if ($ufo->isset_key($row["more"]["transport"], "class"))
$row["more"]["transport"]["class"] = (new MCE_Tables())->get_transport_class($row["more"]["transport"]["class"])[0] ?? 0;
}
if (!empty($row["extend"]))
$row[$row["extend"]] = $ufo->do_work("mce-get-product-extend-" . $row["extend"], $row["product"]);
if ($ufo->isset_key($row["more"], "similar-products")) {
$sps = [];
foreach ($row["more"]["similar-products"] as $item) {
$p = (new UFO_Pages())->get((int) $item);
if ($p) {
$sps[] = [
"id" => (int) $item,
"title" => $p["title"]
];
}
}
$row["more"]["similar-products"] = $sps;
}
return $row;
} else {
return false;
}
} else {
return false;
}
}
/**
* @param $array
* @return mixed
* @throws Exception
*/
protected function productEditValues ($array) {
global $ufo;
$array["link"] = $ufo->web_link() . $ufo->sanitize_link(
(string) (new MCE_Tables())->meta("slug_product")
) . "/" . urlencode($array["link"]);
$ufo->is_json($array["property"], $array["property"]);
$ufo->is_array($array["colors"], $array["colors"]);
$ufo->is_array($array["attributes"], $array["attributes"]);
$ufo->is_json($array["files"], $array["files"]);
$ufo->is_json($array["more"], $array["more"]);
return $array;
}
/**
* @param int $product
* @return bool
* @throws Exception
*/
public function remove (int $product): bool {
global $db;
if ((new UFO_Pages())->delete($product)) {
try {
/** Remove from products */
$db->remove($this->table, "product", $product);
/** Remove from cart */
(new MCE_Cart())->remove_product($product);
/** Remove from favorites */
$this->remove_favorite($product);
return true;
} catch (Exception $e) {
return false;
}
}
return false;
}
/**
* @param int $product
* @param $mid
* @return bool
* @throws Exception
*/
public function remove_favorite (int $product, $mid = null): bool {
global $db;
if (!empty($mid)) {
return $db->remove($this->table_favorite, [
"mid" => $mid,
"product" => $product
]);
} else {
return $db->remove($this->table_favorite, "product", $product);
}
}
/**
* @param bool $paging
* @param int $pp
* @param $limit
* @param $search
* @return array
* @throws Exception
*/
public function get_colors (bool $paging = true, int $pp = 1, $limit = null, $search = null): array {
global $db;
if (empty($search)) {
if ($paging) {
$Colors = $db->pagination($this->table_colors, [
"page" => $pp,
"limit" => $limit ?? $db->meta("table_rows"),
"paging_action" => "mce-colors-paging"
]);
$Colors["rows"] = array_reverse($Colors["rows"]);
} else {
$Colors = array_reverse($db->get($this->table_colors));
}
} else {
$Colors = array_reverse($db->query("SELECT * FROM `%prefix%mce_colors` WHERE `name` LIKE '%".$search."%'"));
}
return $Colors;
}
/**
* @param int $color
* @return false|mixed
* @throws ReflectionException
*/
public function get_color (int $color) {
global $db;
return $db->get($this->table_colors, "id", $color)[0] ?? false;
}
/**
* @param string $name
* @param string $hex
* @return false|int|void
* @throws Exception
*/
public function add_color (string $name, string $hex) {
global $db;
$has = $db->get($this->table_colors, [
"name" => $name,
"hex" => $hex
], null, "OR");
if (empty($has)) {
return $db->insert($this->table_colors, [
"name" => $name,
"hex" => $hex
]);
}
return 0;
}
/**
* @param int $color
* @return bool
* @throws Exception
*/
public function remove_color (int $color): bool {
global $db;
return $db->remove($this->table_colors, "id", $color);
}
/**
* @return int|string
* @throws Exception
*/
public function add_category (array $data) {
return (new UFO_Pages())->create_category($data + [
"from" => "mce"
]);
}
/**
* @param array $data
* @return false|int|string
* @throws Exception
*/
public function edit_category (array $data) {
if (isset($data["category"]))
return (new UFO_Pages())->update_category($data["category"], $data);
return false;
}
/**
* @param int $id
* @return bool
* @throws Exception
*/
public function delete_category (int $id): bool {
return (new UFO_Pages())->delete_category($id);
}
/**
* @param array $info
* @return array
* @throws Exception
*/
public function change_product_info (array $info): array {
global $ufo, $db;
/**
* Status
*/
$status = [
"status" => 403,
"message" => $ufo->lng("Access denied")
];
/**
* Check parameters
*/
$required_params = ["inputs", "type"];
if ($info["type"] == 0)
$required_inputs = ["name"];
else if ($info["type"] == 1)
$required_inputs = ["name"];
else return $status;
/**
* Status
*/
$status = [
"status" => 404,
"message" => $ufo->lng("Parameters not found")
];
if (
!$ufo->has_in_array($required_params, $info) ||
!$ufo->has_in_array($required_inputs, $info["inputs"])
) return $status;
if (isset($info["props"]["%NULL%"]))
unset($info["props"]["%NULL%"]);
/** END **/
/** Add product */
$update = isset($info["update"]) && $info["update"];
$inputs = $info["inputs"];
$properties = $info["props"] ?? [];
$transport = $info["transport"] ?? [];
$colors = $info["colors"] ?? [];
$attributes = $info["attributes"] ?? [];
$oldInfo = $update ? $this->get((int) $info["update"]) : [];
/**
* Page actions
*/
if ($update) {
$oldPageData = (new UFO_Pages())->get((int) $info["update"]);
/**
* Check for exists
*/
if (!isset($db->get($this->table, "product", (int) $info["update"])[0]) || !$oldPageData) {
$status["status"] = 404;
$status["message"] = mce_lng("There is no product with this ID");
return $status;
}
$pageEditor = $ufo->do_work("ufo_page_editor_update", [
"title" => $inputs["name"],
"page" => (int) $info["update"],
"from" => $info["from"] ?? "admin"
]);
} else {
$pageEditor = $ufo->do_work("ufo_page_editor_save", [
"title" => $inputs["name"],
"content" => "",
"short_desc" => "",
"photo" => $inputs["photo"] ?? "[]",
"link" => $inputs["link"] ?? $inputs["name"],
"category" => "[]",
"tags" => "",
"status" => 1,
"type" => "mce",
"script" => [],
"setting" => [],
"from" => $info["from"] ?? "admin"
]);
}
/**
* Product actions
*/
if ($ufo->isset_key($pageEditor, "id") && $pageEditor["status"] == 200) {
if ($ufo->is_bas64($pageEditor["id"] ?? ""))
$pageEditor["id"] = (int) base64_decode($pageEditor["id"]);
if ($info["type"] == 0) {
/** Physical product */
$Data = [
"code" => ($inputs["code"] ?? ($oldInfo["code"] ?? rand(0, 9999) . rand(0, 9999))),
"price" => (int) ($inputs["price"] ?? 0),
"discount" => (int) ($inputs["discount"] ?? 0),
"discount_expire" => (int) ($inputs["discount_expire"] ?? 0),
"tax" => (int) ($inputs["tax"] ?? 0),
"inventory" => (int) ($inputs["inventory"] ?? 0),
"note" => $inputs["note"] ?? "",
"more" => json_encode([
"inventory-alert" => (int) ($inputs["inventory-alert"] ?? 0),
"similar-products" => $info["similarProducts"] ?? [],
"transport" => [
"weight" => (int) ($transport["weight"] ?? 0),
"length" => (int) ($transport["length"] ?? 0),
"width" => (int) ($transport["width"] ?? 0),
"height" => (int) ($transport["height"] ?? 0),
"class" => (int) ($transport["transportClass"] ?? 0)
]
]),
"property" => json_encode($properties, JSON_UNESCAPED_UNICODE),
"colors" => json_encode($colors),
"attributes" => json_encode($attributes, JSON_UNESCAPED_SLASHES),
"bought" => 0,
"type" => $info["type"],
"extend" => $info["extend"] ?? ""
];
} elseif ($info["type"] == 1) {
/** Downloadable product */
if ($ufo->isset_key($inputs, "files")) {
if (!$ufo->is_array($inputs["files"])) {
$FILES = [];
foreach (explode(",", $inputs["files"]) as $item)
$FILES[] = $item;
$inputs["files"] = $FILES;
}
}
$Data = [
"code" => $inputs["code"] ?? ($oldInfo["code"] ?? rand(0, 9999) . rand(0, 9999)),
"price" => (int) ($inputs["price"] ?? 0),
"discount" => (int) ($inputs["discount"] ?? 0),
"discount_expire" => (int) ($inputs["discount_expire"] ?? 0),
"tax" => (int) ($inputs["tax"] ?? 0),
"inventory" => (int) (empty($inputs["inventory"]) ? -1 : $inputs["inventory"]),
"note" => $inputs["note"] ?? "",
"property" => json_encode($properties, JSON_UNESCAPED_UNICODE),
"attributes" => json_encode($attributes, JSON_UNESCAPED_SLASHES),
"files" => json_encode($info["files"] ?? [], JSON_UNESCAPED_UNICODE),
"more" => json_encode([
"similar-products" => $info["similarProducts"] ?? [],
"expire_link" => $inputs["expire-dl"] ?? 12
]),
"bought" => 0,
"type" => $info["type"],
"extend" => $info["extend"] ?? ""
];
} else return $status;
if (!$update) {
$Data += [
"product" => $pageEditor["id"]
];
$insert = $db->insert($this->table, $Data);
} else
$insert = $db->update($this->table, $Data, "product", $pageEditor["id"]);
if ($insert) {
if (isset($info["extend"]))
$ufo->do_work("mce-save-product-extend-" . $info["extend"], array_merge($_POST, $info, [
"mce_product_id" => $pageEditor["id"]
]));
$status = [
"status" => 200,
"message" => $ufo->lng("Done successfully"),
"id" => $pageEditor["id"]
];
} else $status = [
"status" => 503,
"message" => $ufo->lng("System error")
];
return $status;
} else return [
"status" => $pageEditor["status"],
"message" => str_replace($ufo->lng("A page with this name has already been created"), mce_lng("A product with this name has already been created"), $pageEditor["message"])
];
}
/**
* @return int|mixed
* @throws Exception
*/
public function getMaxPrice () {
global $db;
return $db->query("SELECT MAX(`price`) as price FROM `%prefix%".$this->table."`")[0]["price"] ?? 0;
}
/**
* @return int|mixed
* @throws Exception
*/
public function getMinPrice () {
global $db;
return $db->query("SELECT MIN(`price`) as price FROM `%prefix%".$this->table."`")[0]["price"] ?? 0;
}
/**
* @param array $product
* @param $link
* @return false|string
* @throws Exception
*/
public function checkLinkDLAdded (array $product, $link) {
global $ufo, $db;
$member = $ufo->get_member()["uid"] ?? 0;
$row = $db->get($this->table_downloads, [
"pid" => $product["product"],
"link" => $link,
($member == 0 ? "ip" : "mid") => $member == 0 ? $ufo->viewer_ip() : $member,
]); $row = $row[0] ?? false;
if ($row) {
if ($row["expire"] >= $ufo->dateTime())
return $ufo->web_link() . (new MCE_Tables())->meta("slug_dl") . "/" . $row["hash"];
else
$db->remove($this->table_downloads, "id", $row["id"]);
} return false;
}
/**
* @param int $pid
* @param $file
* @return false|string
* @throws Exception
*/
public function addLinkDownload (int $pid, $file) {
global $ufo, $db;
if ($product = $this->get($pid)) {
if (isset($product["files"][$file]["link"])) {
$oldLink = $this->checkLinkDLAdded($product, $product["files"][$file]["link"]);
if (!$oldLink) {
if ($product["files"][$file]) {
$hash = $ufo->hash_generator("sha1");
$insert = $db->insert($this->table_downloads, [
"pid" => $product["product"],
"ip" => $ufo->viewer_ip(),
"mid" => $ufo->get_member()["uid"] ?? 0,
"hash" => $hash,
"name" => $file,
"link" => $product["files"][$file]["link"],
"expire" => !empty($product["more"]["expire_link"]) || $product["more"]["expire_link"] != 0 ? $ufo->addTime(
$product["more"]["expire_link"], "h"
) : 0
]);
return $insert ? $ufo->web_link() . (new MCE_Tables())->meta("slug_dl") . "/" . $hash : false;
}
}
return $oldLink;
}
}
return false;
}
/**
* @return mixed
* @throws Exception
*/
public function count () {
global $db;
return $db->query("SELECT COUNT(`id`) as c FROM `%prefix%".$this->table."`")[0]["c"];
}
/**
* @return bool
* @throws Exception
*/
public function task ( ): bool {
global $ufo, $db;
if (defined("UFO_TASK")) {
$UFO_PAGES = new UFO_Pages();
/** Discounted products expire */
$db->where("discount", 0, ">");
$db->where("discount_expire", 0, ">");
$discounted_products = $db->get($this->table);
foreach ($discounted_products as $product) {
$page = $UFO_PAGES->get($product["product"]);
$days = (new DateTime($page["dateTime"]))->diff(
new DateTime($ufo->dateTime())
)->days;
if ($days > (int) $product["discount_expire"]) {
$db->update($this->table, [
"discount" => 0,
"discount_expire" => 0
], "id", $product["id"]);
}
}
/** END */
return true;
} return false;
}
/**
* @param $sort
* @param $search
* @return string[]|null
* @throws Exception
*/
protected function __sort ($sort, $search = ""): ?array {
global $db;
$fields = null;
$sort = explode("*", $sort);
switch ($sort[0]) {
case "discount":
$db->where("discount", 0, "!=");
break;
case "best-selling":
$db->helper
->where("bought", 0, ">")
->orderBy("SUM(`bought`)");
break;
case "most-popular":
$db->helper->join("comments", "%prefix%" . $this->table . ".product=" . "%prefix%comments.pid AND " . "%prefix%comments.accept=1", "LEFT OUTER");
$db->helper->orderBy("rate");
foreach ($sort as $s) {
if ($s == "limit-null-rate") {
$db->helper->where("rate", "null", "!=");
break;
}
}
$fields = ["AVG(rate) as rate", "%prefix%" . $this->table . ".*"];
break;
case "newest":
$db->helper->orderBy("%prefix%" . $this->table . ".id");
break;
case "cheapest":
$db->helper->orderBy("price", "ASC");
break;
case "most-expensive":
$db->helper->orderBy("price");
break;
}
return $fields;
}
/**
* @param array $filters
* @param $search
* @return void
* @throws Exception
*/
protected function __filters (array $filters, $search = "") {
global $db;
if (isset($filters["price"])) {
if (isset($filters["price"][0]) && isset($filters["price"][1])) {
$db->where("price", (int) $filters["price"][0], ">="); // Min
$db->where("price", (int) $filters["price"][1], "<="); // Max
}
}
if (isset($filters["category"])) {
if (!is_array($filters["category"]))
$filters["category"] = [$filters["category"]];
foreach ($filters["category"] as $category)
$db->where("p.category", "%$category%", "LIKE");
}
if (isset($filters["hasSelling"]))
$db->where("inventory", 0, "!=");
}
}