array(childId) foreach ( $this->getAll($condition) as $item ) { $item_list[$item['parent_id']][$item['id']] = $item; } return $item_list; } // get all categories public function getAll(array $condition = array()){ /*$condition = [ "parent_id" => 1, "status" => 1, ];*/ $bind_types = []; $bind_values = []; $where_clause = ''; if(isset($condition['status'])) { $where_clause .= " AND `status` = ? "; $bind_types[] = 'd'; $bind_values[] = intval($condition['status']); } $query = $this->db->runQuery( " SELECT * FROM `". $this->tb_entity ."` WHERE 1 ".$where_clause." ORDER BY `ordering` DESC LIMIT 5000 ", $bind_types, $bind_values ); return $this->db->fetchAll($query); } protected function beforeCreateItem(array $input_info) : AppResponse { $parent_id = isset($input_info['parent_id']) ? $input_info['parent_id'] : 0; $api_key = (isset($input_info['api_key']) && $input_info['api_key']) ? $input_info['api_key'] : $input_info['title']; $api_key = Security\DataClean::makeInputSafe($api_key, DataType::ID); $api_key = $this->createUniqueAPIKey(0, $api_key); if(!isset($input_info['url_index']) || !$input_info['url_index']) { $input_info['url_index'] = $this->createUniqueUrlIndex(0, $input_info['title']); }else{ $input_info['url_index'] = $this->createUniqueUrlIndex(0, $input_info['url_index']); } $info = array_merge($input_info, array( "parent_id" => $parent_id, "api_key" => $api_key, "create_by" => ADMIN_NAME, "create_time" => CURRENT_TIME, "last_update_by" => ADMIN_NAME, "last_update" => CURRENT_TIME, ) ); return new AppResponse('ok', null, $info); } protected function afterCreateItem($new_item_id, $new_item_info) { //update path&child $this->updatePath($new_item_id); $this->updateChild($new_item_id); $this->updateChild($new_item_info['parent_id']); } protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse { $info = $new_input_info; if(isset($info['url_index'])) { if(!$info['url_index']) { $info['url_index'] = $this->createUniqueUrlIndex($item_id, $info['title']); }else{ $info['url_index'] = $this->createUniqueUrlIndex($item_id, $info['url_index']); } } $info['last_update'] = CURRENT_TIME; $info['last_update_by'] = ADMIN_NAME; return new AppResponse('ok', null, $info); } protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) { //update cat-path for category $this->updatePath($item_id); $this->updateChild($item_id); //update child_ids for new/old parents and parents of parent if($new_item_info['parent_id'] != $old_item_info['parent_id']) { $this->updateChild($new_item_info['parent_id']); $this->updateChild($old_item_info['parent_id']); } } protected function afterDeleteItem($item_id, $item_info){ $this->updateChild($item_info["parent_id"]); } //create an unique request-path protected function createUniqueAPIKey($id, $api_key){ //if exist and belong other id, create a new one $query = $this->db->runQuery("SELECT `id` FROM `".$this->tb_entity."` WHERE `api_key` = ? LIMIT 1 ", ['s'], [$api_key]) ; if($info = $this->db->fetchAssoc($query)){ if($info['id'] != $id) { $new_api_key = $api_key."-1"; return $this->createUniqueAPIKey($id, $new_api_key); } } return $api_key; } protected function updatePathAndChildAll($id, $child_ids, $parent_id, $old_parent_id) { $this->updatePathAndChild($id); //update for childs $list_child_to_update = array_filter(explode(",", $child_ids)); foreach($list_child_to_update as $_id) { if($_id != $id) $this->updatePathAndChild($_id); } //cap nhat lai child list cua danh muc old_parent and new parent id, and parent of these parents $query = $this->db->runQuery( "SELECT cat_path FROM `". $this->tb_entity ."` WHERE `id`= ? OR `id`= ? ", ['d', 'd'], [$parent_id, $old_parent_id] ); $cat_path_all = join(":", array_map(function ($item){ return $item['cat_path']; } , $this->db->fetchAll($query))); $list_parent_to_update = array_unique(array_filter(explode(":", $cat_path_all))); foreach($list_parent_to_update as $_id) { if($_id > 0) $this->updatePathAndChild($_id); } } public function updatePathAndChild($id) { if(!$id) return false; $new_cat_path = $this->findCatPath($id); $new_child_list = $this->findChildList($id); $is_parent = ( $new_child_list === $id) ? 0 : 1; return $this->db->update( $this->tb_entity , [ 'cat_path' => $new_cat_path, 'child_ids' => $new_child_list, 'is_parent' => $is_parent, ], [ 'id' => $id, ] ); } protected function updatePath($id) { if(!$id) return false; $new_cat_path = $this->findCatPath($id); return $this->db->update( $this->tb_entity , [ 'cat_path' => $new_cat_path, ], [ 'id' => $id, ] ); } //update childs for current id and its parents and its parents' parents.... protected function updateChild($id) { if(!$id) return false; $query = $this->db->runQuery("SELECT `cat_path` FROM `".$this->tb_entity."` WHERE `id` = ? LIMIT 1 ", ['d'], [$id]) ; if($item_info = $this->db->fetchAssoc($query)){ $cat_id_list = array_filter(explode(":", $item_info['cat_path'])); foreach ($cat_id_list as $_id) { $new_child_list = $this->findChildList($_id); $is_parent = ( $new_child_list === $_id) ? 0 : 1; $this->db->update( $this->tb_entity , [ 'child_ids' => $new_child_list, 'is_parent' => $is_parent, ], [ 'id' => $_id, ] ); } } return true; } protected function _buildQueryConditionExtend(array $condition) : ?array { $catCondition = []; $bind_types = []; $bind_values = []; return array(join(" ", $catCondition), $bind_types, $bind_values); } //build category path 0:parent:categoryId protected function findCatPath($categoryId){ $path = ":".$categoryId; $query = $this->db->runQuery("SELECT `parent_id` FROM `".$this->tb_entity."` WHERE `id` = ? LIMIT 1", ['d'], [$categoryId]); if($rs = $this->db->fetchAssoc($query)){ if($rs['parent_id']) $path .= $this->findCatPath($rs['parent_id']); } return $path; } //lay toan bo cac muc la con protected function findChildList($p_category_id){ $all_categories = $this->getAllByParent(); $list = $p_category_id; if(isset($all_categories[$p_category_id])) { foreach ( $all_categories[$p_category_id] as $rs ) { $list .= ",". $this->findChildList($rs['id']); } } return $list; } protected function getAllParent(array $condition = []) { $cache_key = 'all-category-by-parent-'.$this->getEntityType(); return self::getCache($cache_key, function () use ($condition){ return $this->getAllByParent($condition); }); } }