[ 'creator' => ['class_name' => 'User', 'foreign_key' => 'creator_id'], 'updater' => ['class_name' => 'User', 'foreign_key' => 'last_updated_by'], 'parent' => ['class_name' => "ForumPost", 'foreign_key' => 'parent_id'] ], 'has_many' => [ 'children' => [function() { $this->order('id'); }, 'class_name' => "ForumPost", 'foreign_key' => 'parent_id'] ] ]; } protected function callbacks() { return [ 'after_create' => ['initialize_last_updated_by', 'update_parent_on_create', 'clear_cache'], 'before_destroy' => ['update_parent_on_destroy'], 'before_validation' => ['validate_title', 'validate_lock'] ]; } protected function validations() { return [ 'body' => [ 'length' => ['minimum' => 1, 'message' => "You need to enter a body"] ] ]; } /* LockMethods { */ static public function lock($id) { # Run raw SQL to skip the lock check self::connection()->executeSql("UPDATE forum_posts SET is_locked = TRUE WHERE id = ?", $id); } static public function unlock($id) { # Run raw SQL to skip the lock check self::connection()->executeSql("UPDATE forum_posts SET is_locked = FALSE WHERE id = ?", $id); } public function validate_lock() { if ($this->root()->is_locked) { $this->errors()->add('base', "Thread is locked"); return false; } return true; } /* } StickyMethods { */ static public function stick($id) { # Run raw SQL to skip the lock check self::connection()->executeSql("UPDATE forum_posts SET is_sticky = TRUE WHERE id = ?", $id); } static public function unstick($id) { # Run raw SQL to skip the lock check self::connection()->executeSql("UPDATE forum_posts SET is_sticky = FALSE WHERE id = ?", $id); } /* } ParentMethods { */ public function update_parent_on_destroy() { if (!$this->is_parent()) { $p = $this->parent; $p->updateAttributes(['response_count' => $p->response_count - 1]); } } public function update_parent_on_create() { if (!$this->is_parent()) { $p = $this->parent; $p->updateAttributes(['updated_at' => $this->updated_at, 'response_count' => $p->response_count + 1, 'last_updated_by' => $this->creator_id]); } } public function is_parent() { return !(bool)$this->parent_id; } public function root() { if ($this->is_parent()) { return $this; } else { return $this->parent; } } public function root_id() { if ($this->is_parent()) { return $this->id; } else { return $this->parent_id; } } /* } ApiMethods { */ public function api_attributes() { return [ 'body' => $this->body, 'creator' => $this->author(), 'creator_id' => $this->creator_id, 'id' => $this->id, 'parent_id' => $this->parent_id, 'title' => $this->title, 'updated_at' => $this->updated_at, 'pages' => ceil((!$this->response_count ? 1 : $this->response_count) / 30) ]; } public function asJson(array $params = []) { return $this->api_attributes(); } public function toXml(array $options = []) { return parent::toXml(array_merge($options, ['root' => "forum-post", 'attributes' => $this->api_attributes()])); } /* } */ static public function updated($user) { $query = ForumPost::none(); if (!$user->is_anonymous()) $query->where("creator_id <> " . $user->id); $newest_topic = $query->order("id desc")->limit(1)->select("created_at")->first(); if (!$newest_topic) return false; return $newest_topic->created_at > $user->last_forum_topic_read_at; } public function validate_title() { if ($this->is_parent()) { if (!$this->title || !preg_match('/\S/', $this->title)) { $this->errors()->add('title', "missing"); return false; } } return true; } public function initialize_last_updated_by() { if ($this->is_parent()) { $this->updateAttribute('last_updated_by', $this->creator_id); } } public function last_updater() { return $this->updater ? $this->updater->name : CONFIG()->default_guest_name; } public function author() { return $this->creator->name; } protected function clear_cache() { Rails::cache()->delete("forum_posts"); } }