Esempio n. 1
0
 /**
  * Pushes the post to the specified board, as a new thread or as a reply.
  * This autoatically handles concurrency issues. Creating a new reply without
  * using this method is forbidden by the `creating` event in ::boot.
  *
  *
  * @param  App\Board  &$board
  * @param  App\Post   &$thread
  * @return void
  */
 public function submitTo(Board &$board, &$thread = null)
 {
     $this->board_uri = $board->board_uri;
     $this->author_ip = inet_pton(Request::ip());
     $this->reply_last = $this->freshTimestamp();
     $this->bumped_last = $this->reply_last;
     $this->setCreatedAt($this->reply_last);
     $this->setUpdatedAt($this->reply_last);
     if (!is_null($thread) && !$thread instanceof Post) {
         $thread = $board->getLocalThread($thread);
         $this->reply_to = $thread->post_id;
         $this->reply_to_board_id = $thread->board_id;
     }
     // Store the post in the database.
     DB::transaction(function () use($board, $thread) {
         // The objective of this transaction is to prevent concurrency issues in the database
         // on the unique joint index [`board_uri`,`board_id`] which is generated procedurally
         // alongside the primary autoincrement column `post_id`.
         // First instruction is to add +1 to posts_total and set the last_post_at on the Board table.
         DB::table('boards')->where('board_uri', $this->board_uri)->increment('posts_total');
         DB::table('boards')->where('board_uri', $this->board_uri)->update(['last_post_at' => $this->created_at]);
         // Second, we record this value and lock the table.
         $boards = DB::table('boards')->where('board_uri', $this->board_uri)->lockForUpdate()->select('posts_total')->get();
         $posts_total = $boards[0]->posts_total;
         // Optionally, the OP of this thread needs a +1 to reply count.
         if ($thread instanceof Post) {
             if (!$this->isBumpless() && !$thread->isBumplocked()) {
                 $thread->bumped_last = $this->created_at;
                 // We explicitly set the updated_at to what it is now.
                 // If we didn't, this would change.
                 // We don't want that because it screws up the API and
                 // makes it think the OP post has had its content edited.
                 $thread->updated_at = $thread->updated_at;
             }
             $thread->reply_last = $this->created_at;
             $thread->reply_count += 1;
             $thread->save();
         }
         // Optionally, we also expend the adventure.
         $adventure = BoardAdventure::getAdventure($board);
         if ($adventure) {
             $this->adventure_id = $adventure->adventure_id;
             $adventure->expended_at = $this->created_at;
             $adventure->save();
         }
         // Finally, we set our board_id and save.
         $this->board_id = $posts_total;
         $this->author_id = $this->makeAuthorId();
         $this->save();
         // Queries and locks are handled automatically after this closure ends.
     });
     // Process uploads.
     $uploads = [];
     if (is_array($files = Input::file('files'))) {
         $uploads = array_filter($files);
     }
     if (count($uploads) > 0) {
         foreach ($uploads as $uploadIndex => $upload) {
             if (file_exists($upload->getPathname())) {
                 FileStorage::createAttachment($upload, $this);
             }
         }
     }
     // Finally fire event on OP, if it exists.
     if ($thread instanceof Post) {
         Event::fire(new ThreadNewReply($thread));
     }
 }