Files
admin_hura_8/inc/Hura8/System/Model/RelationModel.php
2024-01-29 10:39:53 +07:00

342 lines
12 KiB
PHP

<?php
namespace Hura8\System\Model;
use Hura8\Database\iConnectDB;
use Hura8\System\Security\DataClean;
use Hura8\System\Security\DataType;
class RelationModel
{
/* @var $db iConnectDB */
protected $db;
protected $tb_relation = "tb_relation";
protected $main_item_type= '';
protected $main_item_id= 0;
public function __construct($main_item_type, $main_item_id = 0) {
$this->db = get_db('', ENABLE_DB_DEBUG);
$this->main_item_type = $main_item_type;
$this->main_item_id = $main_item_id;
}
//given related_type and type_id, get all the main item ids
public function getMainItems($related_item_type, $related_item_id = 0, array $condition = [], $return_type = 'list') {
$where_clause = " AND `main_item_type` = '" . $this->db->escape($this->main_item_type) . "'
AND `main_item_id` = '".intval($this->main_item_id)."' ";
$where_clause .= " AND `related_item_type` = '" . $this->db->escape($related_item_type) . "' ";
if($related_item_id) $where_clause .= " AND `related_item_id` = '".intval($related_item_id)."' ";
//excluded_ids
if(isset($condition["excluded_ids"]) && $condition["excluded_ids"] ){
$list_ids = DataClean::makeListOfInputSafe(explode(",", $condition["excluded_ids"]), DataType::INTEGER);
if(sizeof($list_ids)) $where_clause .= " AND `related_item_id` NOT IN (".join(',', $list_ids ).") ";
}
//included_ids
if(isset($condition["included_ids"]) && $condition["included_ids"] ){
$list_ids = DataClean::makeListOfInputSafe(explode(",", $condition["included_ids"]), DataType::INTEGER);
if(sizeof($list_ids)) $where_clause .= " AND `related_item_id` IN (".join(',', $list_ids ).") ";
}
if($return_type == 'total') {
$query = $this->db->query("
SELECT COUNT(*) as total FROM `".$this->tb_relation."`
WHERE 1 " . $where_clause . " ");
$total = 0;
if ($rs = $this->db->fetchAssoc($query)) {
$total = $rs['total'];
}
return $total;
} else {
$page = isset($condition['page']) ? intval($condition['page']) : 1;
$numPerPage = isset($condition['numPerPage']) ? intval($condition['numPerPage']) : 10;
$query = $this->db->query("
SELECT `related_item_id` FROM `". $this->tb_relation ."`
WHERE 1 " . $where_clause . "
ORDER BY `ordering` DESC, `id` DESC
LIMIT " . ($page - 1) * $numPerPage . ", ". $numPerPage ."
");
$result = array();
foreach ( $this->db->fetchAll($query) as $info ) {
$result[] = $info['related_item_id'];
}
return $result;
}
}
public function updateOrdering($related_item_id, $new_order) {
$this->db->runQuery(
"UPDATE `".$this->tb_relation."` SET
`ordering` = ?
WHERE `main_item_type` = ? AND `main_item_id` = ? AND `related_item_id` = ? ",
['d', 's', 'd', 'd'],
[ $new_order, $this->main_item_type, $this->main_item_id, $related_item_id ]
);
return [
'status' => 'success',
'message' => ''
];
}
//@warn: this does not check if records exist.
public function create(array $related_items, $both_way_relation = true) {
$build_insert = array();
foreach ($related_items as $item) {
if(!$this->checkExist($this->main_item_type, $this->main_item_id, $item['type'], $item['id'])) {
$build_insert[] = [
"main_item_type" => $this->main_item_type,
"main_item_id" => intval($this->main_item_id),
"related_item_type" => $item['type'],
"related_item_id" => intval($item['id']),
"create_time" => CURRENT_TIME,
"create_by" => ADMIN_NAME,
];
}
//if 2-way relation, create item->main
if($both_way_relation) {
if(!$this->checkExist($item['type'], $item['id'], $this->main_item_type, $this->main_item_id)) {
$build_insert[] = [
"main_item_type" => $item['type'],
"main_item_id" => intval($item['id']),
"related_item_type" => $this->main_item_type,
"related_item_id" => intval($this->main_item_id),
"create_time" => CURRENT_TIME,
"create_by" => ADMIN_NAME,
];
}
}
}
if(sizeof($build_insert)) {
$this->db->bulk_insert($this->tb_relation, $build_insert);
return [
'status' => 'success',
'message' => ''
];
}
return [
'status' => 'error',
'message' => 'Đã tồn tại'
];
}
public function checkExist($main_item_type, $main_item_id, $related_item_type, $related_item_id) {
// itself
if($main_item_type == $related_item_type && $main_item_id == $related_item_id) {
return true;
}
$query = $this->db->runQuery(
"SELECT id FROM `".$this->tb_relation."`
WHERE `main_item_type` = ? AND `main_item_id` = ? AND `related_item_type` = ? AND `related_item_id` = ?
LIMIT 1" ,
[
's', 'd', 's', 'd'
],
[
$main_item_type,
intval($main_item_id),
$related_item_type,
intval($related_item_id)
]
);
if($rs = $this->db->fetchAssoc($query)) {
return $rs['id'];
}
return false;
}
//remove a related-item
public function remove($related_item_type, $related_item_id, $remove_both_way = true) {
$main_item_query = ( $this->main_item_id ) ? " `main_item_id` = '".intval($this->main_item_id)."' AND " : "";
$this->db->query("DELETE FROM `".$this->tb_relation."` WHERE
`main_item_type` = '" . $this->db->escape($this->main_item_type) . "' AND
". $main_item_query ."
`related_item_type` = '".$this->db->escape($related_item_type)."' AND
`related_item_id` = '".intval($related_item_id)."' ");
if($remove_both_way) {
$related_item_query = ( $this->main_item_id ) ? " `related_item_id` = '".intval($this->main_item_id)."' AND " : "";
$this->db->query("DELETE FROM `".$this->tb_relation."` WHERE
`related_item_type` = '" . $this->db->escape($this->main_item_type) . "' AND
" . $related_item_query . "
`main_item_type` = '".$this->db->escape($related_item_type)."' AND
`main_item_id` = '".intval($related_item_id)."' ");
}
return [
'status' => 'success',
'message' => ''
];
}
//remove all relate items
public function truncate() {
$this->db->runQuery(
"DELETE FROM `".$this->tb_relation."` WHERE `main_item_type` = ? AND `main_item_id` = ? ",
[ 's', 's' ],
[ $this->main_item_type, $this->main_item_id ]
);
}
//count related items
public function getRelatedItemCount() {
$query = $this->db->runQuery(
"
SELECT `related_item_type`, COUNT(`related_item_id`) AS total FROM `". $this->tb_relation ."`
WHERE `main_item_type` = ? AND `main_item_id` = ?
GROUP BY `related_item_type`
",
[ 's', 's' ], [ $this->main_item_type, $this->main_item_id ]
);
$result = array();
foreach ( $this->db->fetchAll($query) as $info ) {
$result[$info['related_item_type']] = $info['total'];
}
return $result;
}
//extend getRelatedItems to get for list of main_item_ids
public function getRelatedItemsForList(array $main_item_list_ids, array $related_item_types = []) {
if(!sizeof($main_item_list_ids)) return [];
$bind_values = $main_item_list_ids;
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($main_item_list_ids, 'int');
$condition = " AND `main_item_id` IN (". $parameterized_ids .") ";
$bind_types[] = 's';
$bind_values[] = $this->main_item_type;
$condition .= " AND `main_item_type` = ? ";
if(sizeof($related_item_types)) {
$type_condition = [];
foreach ($related_item_types as $_type) {
$type_condition[] = " `related_item_type` = ? ";
$bind_types[] = 's';
$bind_values[] = $_type;
}
$condition .= " AND ( ".join(' OR ', $type_condition )." ) ";
}
$query = $this->db->runQuery("
SELECT
`main_item_id` ,
`related_item_type`,
`related_item_id`,
`ordering`
FROM `". $this->tb_relation ."`
WHERE 1 ". $condition ."
ORDER BY `ordering` DESC, `id` DESC
LIMIT 5000
", $bind_types, $bind_values);
$result = array();
foreach ( $this->db->fetchAll($query) as $info ) {
$result[$info['main_item_id']][$info['related_item_type']][$info['related_item_id']] = [
"item_id" => $info['related_item_id'],
"ordering" => $info['ordering'],
];
}
//final result
$final_result = [];
foreach ($main_item_list_ids as $_id) {
$final_result[$_id] = (isset($result[$_id])) ? $result[$_id] : false;
}
return $final_result;
}
//get all related items and group them by type
public function getRelatedItems(array $related_item_types = []) {
$bind_types = ['s', 's'];
$bind_values = [$this->main_item_type, $this->main_item_id];
$condition = "";
if(sizeof($related_item_types)) {
$type_condition = [];
foreach ($related_item_types as $_type) {
$type_condition[] = " `related_item_type` = ? ";
$bind_types[] = 's';
$bind_values[] = $_type;
}
$condition .= " AND ( ".join(' OR ', $type_condition )." ) ";
}
$query = $this->db->runQuery("
SELECT
`related_item_type`,
`related_item_id`,
`ordering`
FROM `". $this->tb_relation ."`
WHERE `main_item_type` = ? AND `main_item_id` = ? ". $condition ."
ORDER BY `ordering` DESC, `id` DESC
LIMIT 5000
", $bind_types, $bind_values );
$result = array();
foreach ( $this->db->fetchAll($query) as $info ) {
$result[$info['related_item_type']][$info['related_item_id']] = [
"item_id" => $info['related_item_id'],
"ordering" => $info['ordering'],
];
}
//check if we get only single type, then return all the results
if(sizeof($related_item_types) == 1) {
$related_item_type = $related_item_types[0];
return isset($result[$related_item_type]) ? $result[$related_item_type] : array();
}
return $result;
}
}