= 1) ? ($page - 1) : 0; $offset *= 10; $sql = 'SELECT * FROM posts ORDER BY create_at DESC LIMIT ?,10'; $query = $db->prepare($sql); $query->bindValue(1, $offset, \PDO::PARAM_INT); $query->execute(); $posts = $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); $offset += 10; $query->bindValue(1, $offset, \PDO::PARAM_INT); $query->execute(); $next = $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); $sql = 'SELECT id, keyword, COUNT(id) AS num_of_posts FROM ('. 'tags JOIN post_tag ON id=tag_id) GROUP BY id ORDER BY keyword'; $query = $db->prepare($sql); $query->execute(); $tags = $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); $is_last = count($next) == 0 ? true : false; return view('post.index', [ 'posts' => $posts, 'tags' => $tags, 'page' => $page, 'is_last' => $is_last, 'pager_uri' => '' ]); } public function showCreate() { return view('post.create', [ 'title' => '', 'content' => '', 'tags' => '' ]); } public function show($id) { $post = $this->getPost($id); if ($post != null) { return view('post.show', [ 'post' => $post, 'tags' => $this->getTags($id), 'comments' => $this->getComments($id) ]); } throw new \Phroute\Phroute\Exception\HttpRouteNotFoundException; } public function showUpdate($id) { if (! $this->isAuthor($id)) { header('HTTP/1.0 403 Forbidden'); die(); return false; } if ($post = $this->getPostWithTags($id)) { return view('post.edit', ['post' => $post]); } throw new \Phroute\Phroute\Exception\HttpRouteNotFoundException; } public function create() { if (! $this->titleValid()) { header('Location: /post/create'); return false; } $id = $this->setPost(); $tags = array_values(array_filter( array_map('trim', explode(',', $_POST['tags'])) )); $this->setTags($tags); $this->syncPostTag($id, $tags); header("Location: /post/$id"); return false; } public function update($id) { if (! $this->isAuthor($id)) { header('HTTP/1.0 403 Forbidden'); die(); return false; } if (! $this->titleValid()) { header("Location: /post/$id/edit"); return false; } $this->updatePost($id); $tags = array_values(array_filter( array_map('trim', explode(',', $_POST['tags'])) )); $this->setTags($tags); $this->syncPostTag($id, $tags); header("Location: /post/$id"); return false; } public function delete($id) { if (! $this->isAuthor($id)) { header('HTTP/1.0 403 Forbidden'); die(); return false; } $sql = 'DELETE FROM posts WHERE id=?'; $query = db()->prepare($sql); $query->execute([$id]); $path = parse_url($_SERVER['HTTP_REFERER'])['path']; if (preg_match('/^\/post\//', $path)) { header('Location: /'); return false; } header("Location: $path"); return false; } private function isAuthor($id) { $sql = 'SELECT author FROM posts WHERE id=?'; $query = db()->prepare($sql); $query->execute([$id]); $post = $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); return (count($post) != 0 && $post[0]->author == $_SESSION['username']); } private function titleValid() { if (empty(trim($_POST['title']))) { $_SESSION['errors'] = ['Post title cannot be empty.']; $_SESSION['inputs'] = [ 'title' => $_POST['title'], 'content' => $_POST['content'], 'tags' => $_POST['tags'] ]; return false; } return true; } private function getPost($id) { $sql = 'SELECT p.*, COUNT(c.id) AS num_of_comments FROM posts AS p ' . 'LEFT JOIN comments AS c ON p.id=c.comment_to WHERE p.id=:id'; $query = db()->prepare($sql); $query->bindValue(':id', $id, \PDO::PARAM_INT); $query->execute(); $post = $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); if (count($post) != 0) { return $post[0]; } return null; } private function getTags($id) { $sql = 'SELECT * FROM tags WHERE id IN ( ' . "SELECT tag_id FROM post_tag WHERE post_id=? ) ORDER BY keyword"; $query = db()->prepare($sql); $query->execute([$id]); return $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); } private function getComments($id) { $sql = 'SELECT c.*, u.email FROM comments AS c, users AS u ' . 'WHERE c.comment_to=? AND c.author=u.name ORDER BY c.create_at'; $query = db()->prepare($sql); $query->execute([$id]); return $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); } private function getPostWithTags($id) { $sql = "SELECT p.*, GROUP_CONCAT(DISTINCT t.keyword SEPARATOR ', ') AS tags " . 'FROM posts AS p, tags AS t WHERE p.id=:id AND t.id IN ( ' . 'SELECT tag_id FROM post_tag WHERE post_id=:id ) ORDER BY t.keyword'; $query = db()->prepare($sql); $query->bindValue(':id', $id, \PDO::PARAM_INT); $query->execute(); $post = $query->fetchAll(\PDO::FETCH_CLASS, 'Core\\Record'); if (count($post) != 0) { return $post[0]; } return null; } private function setPost() { $db = db(); $sql = 'INSERT INTO posts VALUES (NULL, ?, ?, ?, DEFAULT, DEFAULT)'; $query = $db->prepare($sql); $query->execute([ trim($_POST['title']), trim($_POST['content']), $_SESSION['username'] ]); return $db->lastInsertId(); } private function updatePost($id) { $sql = 'UPDATE posts SET title=?, content=? WHERE id=?'; $query = db()->prepare($sql); $query->execute([ trim($_POST['title']), trim($_POST['content']), $id ]); } private function setTags($tags) { if (count($tags) != 0) { $rows = []; foreach ($tags as $tag) { array_push($rows, "(NULL, ?)"); } $sql = 'INSERT INTO tags VALUES ' . implode(', ', $rows) . ' ON DUPLICATE KEY UPDATE keyword=keyword'; $query = db()->prepare($sql); $query->execute($tags); } } private function syncPostTag($post_id, $tags) { $db = db(); if (count($tags) != 0) { $tuple_holders = []; $element_holders = []; $rows = []; $tag_ids = $this->tagsToIds($tags); foreach ($tag_ids as $tag_id) { array_push($tuple_holders, '(?, ?)'); array_push($element_holders, '?'); array_push($rows, $post_id, $tag_id); } $sql = 'INSERT INTO post_tag VALUES ' . implode(', ', $tuple_holders) . ' ON DUPLICATE KEY UPDATE post_id=post_id'; $query = $db->prepare($sql); $query->execute($rows); $sql = 'DELETE FROM post_tag WHERE post_id=? AND tag_id NOT IN ' . '(' . implode(', ', $element_holders) . ')'; $query = $db->prepare($sql); $query->bindValue(1, $post_id, \PDO::PARAM_INT); foreach ($tag_ids as $index => $tag_id) { $query->bindValue($index + 2, $tag_id, \PDO::PARAM_INT); } $query->execute(); } else { $sql = 'DELETE FROM post_tag WHERE post_id=?'; $query = $db->prepare($sql); $query->execute([$post_id]); } } private function tagsToIds($tags) { $element_holders = []; foreach ($tags as $tag) { array_push($element_holders, '?'); } $sql = 'SELECT DISTINCT id FROM tags WHERE keyword IN ' . '(' . implode(', ', $element_holders) . ') ORDER BY id'; $query = db()->prepare($sql); $query->execute($tags); return $query->fetchAll(\PDO::FETCH_COLUMN, 0); } }