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; } }