sql_connection = $sql_connection; $this->hostname = $hostname; $this->debugging = false; } private function _dbg($message) { if($this->debugging) { echo $message; } } private function _exec($qery, $argtypes = '', ...$args) { $stmt = $this->sql_connection->prepare($qery); if($argtypes != ""){ $stmt->bind_param($argtypes, ...$args); } $stmt->execute(); return $stmt->get_result(); } private function clear_post_settings_cache($post_path) { $post_path = sanitize_post_path($post_path); $this->_exec(" UPDATE posts SET post_settings_cache=NULL WHERE host = ? AND post_path LIKE ?; ", "ss", $this->hostname, $post_path . "%"); } public function stub_postdata($path) { $post_path = sanitize_post_path($path); $path_depth = substr_count($post_path, "/"); $qry = " INSERT INTO posts (host, post_path, post_path_depth) VALUES ( ?, ?, ?) AS new ON DUPLICATE KEY UPDATE post_path=new.post_path;"; $this->_exec($qry, "ssi", $this->hostname, $post_path, $path_depth); } public function stub_postdata_tree($path) { $post_path = sanitize_post_path($path); while(true) { if($post_path == '/') { $post_path = ''; } try { $this->stub_postdata($post_path); } catch(Exception $e) { } $post_path = dirname($post_path); if(strlen($post_path) == 0) { break; } } } public function set_postdata($data) { $data['path'] = sanitize_post_path($data['path']); $post_path = $data['path']; unset($data['path']); $this->stub_postdata_tree($post_path); $data['title'] ??= basename($post_path); $post_tags = $data['tags'] ?? []; array_push($post_tags, 'path:' . $post_path ); $sql_args = [ $this->hostname, $post_path, substr_count($post_path, "/"), $data['title'], taglist_to_sql_string($post_tags), $data['brief'] ?? null ]; unset($data['title']); unset($data['brief']); $post_markdown = $data['markdown'] ?? null; unset($data['markdown']); unset($data['html']); array_push($sql_args, json_encode($data)); $qry = "INSERT INTO posts (host, post_path, post_path_depth, post_title, post_tags, post_brief, post_metadata, post_settings_cache) VALUES ( ?, ?, ?, ?, ?, ?, ?, null) AS new ON DUPLICATE KEY UPDATE post_title=new.post_title, post_tags=new.post_tags, post_brief=new.post_brief, post_metadata=new.post_metadata, post_updated_at=CURRENT_TIMESTAMP; "; $this->_exec($qry, "ssissss", ...$sql_args); if(isset($post_markdown)) { $this->set_post_markdown($this->sql_connection->insert_id, $post_markdown); } $this->clear_post_settings_cache($post_path); } public function set_post_markdown($id, $markdown) { $qry = "INSERT INTO post_markdown ( post_id, post_markdown ) VALUES (?, ?) AS new ON DUPLICATE KEY UPDATE post_markdown=new.post_markdown; "; $this->_exec($qry, "is", $id, $markdown); } private function get_post_settings($post_path) { $post_path = sanitize_post_path($post_path); $this->_dbg("-> gps: getting path " . $post_path . "\n"); $post_settings = $this->_exec(" SELECT post_settings_cache FROM posts WHERE post_path = ? AND host = ? ", "ss", $post_path, $this->hostname)->fetch_assoc(); if(!isset($post_settings)) { $this->_dbg("-> gps: Returning because of no result\n"); return []; } if(isset($post_settings['post_settings_cache'])) { $result = json_decode($post_settings['post_settings_cache'], true); if($this->debugging) { echo "-> gps: Returning because of cached result:\n"; echo "--> " . json_encode($result) . "\n"; } return $result; } $parent_settings = []; if($post_path != "") { $parent_settings = $this->get_post_settings(dirname($post_path)); } $post_settings = []; $post_metadata = $this->_exec(" SELECT post_path, post_metadata FROM posts WHERE post_path = ? AND host = ? ", "ss", $post_path, $this->hostname)->fetch_assoc(); if(isset($post_metadata['post_metadata'])) { $post_metadata = json_decode($post_metadata['post_metadata'], true); if(isset($post_metadata['settings'])) { $post_settings = $post_metadata['settings']; } } $post_settings = array_merge($parent_settings, $post_settings); $this->_dbg("-> gps: Merged post settings are " . json_encode($post_settings) . ", saving...\n"); $this->_exec(" UPDATE posts SET post_settings_cache=? WHERE post_path=? AND host=? ", "sss", json_encode($post_settings), $post_path, $this->hostname); return $post_settings; } private function process_postdata($data) { if(!isset($data)) { return null; } if(!isset($data['post_path'])) { echo "ERROR, trying to get a post data package without path!"; die(); } $outdata = []; foreach($this::SQL_READ_COLUMNS as $key) { if(isset($data['post_' . $key])) { $outdata[$key] = $data['post_' . $key]; } } $post_metadata = json_decode($data['post_metadata'] ?? '{}', true); $post_settings = []; if(isset($data['post_settings_cache'])) { $post_settings = json_decode($data['post_settings_cache'], true); } else { $post_settings = $this->get_post_settings($data['post_path']); } $outdata = array_merge($post_settings, $post_metadata, $outdata); return $outdata; } public function get_postdata($path) { $path = sanitize_post_path($path); $qry = " SELECT * FROM posts WHERE post_path = ? AND host = ?; "; $data = $this->_exec($qry, "ss", $path, $this->hostname)->fetch_assoc(); return $this->process_postdata($data); } public function get_post_children($path, $limit = 50, $depth_start = 1, $depth_end = 1, $order_by = 'path') { $path = sanitize_post_path($path); $path_depth = substr_count($path, "/"); $allowed_ordering = [ 'path' => true, 'path DESC' => true, 'created_at' => true, 'created_at DESC' => true, 'modified_at' => true, 'modified_at DESC' => true ]; if(!isset($allowed_ordering[$order_by])) { throw new Exception('Children ordering not allowed'); } $order_by = 'post_' . $order_by; if($this->debugging) { echo "-> GPC: Getting children for path " . $path; } $qry = " SELECT * FROM posts WHERE post_path_depth BETWEEN ? AND ? AND post_path LIKE ? ORDER BY " . $order_by . " LIMIT ?"; $data = $this->_exec($qry, "iisi", $path_depth + $depth_start, $path_depth + $depth_end, $path.'/%', $limit )->fetch_all(MYSQLI_ASSOC); $outdata = []; foreach($data AS $post_element) { $outdata[$post_element['post_path']] = $this->process_postdata($post_element); } return $outdata; } public function get_post_markdown($id) { $qry = "SELECT post_markdown FROM post_markdown WHERE post_id = ? "; $data = $this->_exec($qry, "i", $id)->fetch_assoc(); if(!isset($data)) { return ""; } return $data['post_markdown']; } } ?>