/** * @param SearchCriteria $criteria * @param int|null $limit * @param int $offset * @param array $load An array of relationships to load on the results. * @return SearchResults */ public function search(SearchCriteria $criteria, $limit = null, $offset = 0, array $load = []) { $actor = $criteria->actor; $query = $this->discussions->query()->whereVisibleTo($actor); // Construct an object which represents this search for discussions. // Apply gambits to it, sort, and paging criteria. Also give extensions // an opportunity to modify it. $search = new DiscussionSearch($query->getQuery(), $actor); $this->gambits->apply($search, $criteria->query); $this->applySort($search, $criteria->sort); $this->applyOffset($search, $offset); $this->applyLimit($search, $limit + 1); event(new DiscussionSearchWillBePerformed($search, $criteria)); // Execute the search query and retrieve the results. We get one more // results than the user asked for, so that we can say if there are more // results. If there are, we will get rid of that extra result. $discussions = $query->get(); if ($areMoreResults = $limit > 0 && $discussions->count() > $limit) { $discussions->pop(); } // The relevant posts relationship isn't a typical Eloquent // relationship; rather, we need to extract that information from our // search object. We will delegate that task and prevent Eloquent // from trying to load it. if (in_array('relevantPosts', $load)) { $this->loadRelevantPosts($discussions, $search); $load = array_diff($load, ['relevantPosts', 'relevantPosts.discussion', 'relevantPosts.user']); } Discussion::setStateUser($actor); $discussions->load($load); return new SearchResults($discussions, $areMoreResults); }
/** * @param \Flarum\Core\Discussions\Commands\DeleteDiscussion $command * @return \Flarum\Core\Discussions\Discussion */ public function handle(DeleteDiscussion $command) { $actor = $command->actor; $discussion = $this->discussions->findOrFail($command->discussionId, $actor); $discussion->assertCan($actor, 'delete'); event(new DiscussionWillBeDeleted($discussion, $actor, $command->data)); $discussion->delete(); $this->dispatchEventsFor($discussion); return $discussion; }
/** * @param ReadDiscussion $command * @return \Flarum\Core\Discussions\DiscussionState * @throws \Flarum\Core\Exceptions\PermissionDeniedException */ public function handle(ReadDiscussion $command) { $actor = $command->actor; if (!$actor->exists) { throw new PermissionDeniedException(); } $discussion = $this->discussions->findOrFail($command->discussionId, $actor); $state = $discussion->stateFor($actor); $state->read($command->readNumber); event(new DiscussionStateWillBeSaved($state)); $state->save(); $this->dispatchEventsFor($state); return $state; }
/** * @param EditDiscussion $command * @return \Flarum\Core\Discussions\Discussion * @throws \Flarum\Core\Exceptions\PermissionDeniedException */ public function handle(EditDiscussion $command) { $actor = $command->actor; $data = $command->data; $attributes = array_get($data, 'attributes', []); $discussion = $this->discussions->findOrFail($command->discussionId, $actor); if (isset($attributes['title'])) { $discussion->assertCan($actor, 'rename'); $discussion->rename($attributes['title'], $actor); } event(new DiscussionWillBeSaved($discussion, $actor, $data)); $discussion->save(); $this->dispatchEventsFor($discussion); return $discussion; }
/** * {@inheritdoc} */ protected function conditions(Search $search, array $matches, $negate) { if (!$search instanceof DiscussionSearch) { throw new LogicException('This gambit can only be applied on a DiscussionSearch'); } $actor = $search->getActor(); if ($actor->exists) { $readIds = $this->discussions->getReadIds($actor); $search->getQuery()->where(function ($query) use($readIds, $negate, $actor) { if (!$negate) { $query->whereNotIn('id', $readIds)->where('last_time', '>', $actor->read_time ?: 0); } else { $query->whereIn('id', $readIds)->orWhere('last_time', '<=', $actor->read_time ?: 0); } }); } }
/** * Get a single discussion, ready to be serialized and assigned to the * JsonApi response. * * @param JsonApiRequest $request * @param Document $document * @return \Flarum\Core\Discussions\Discussion */ protected function data(JsonApiRequest $request, Document $document) { $discussionId = $request->get('id'); $actor = $request->actor; $discussion = $this->discussions->findOrFail($discussionId, $actor); $discussion->posts_ids = $discussion->postsVisibleTo($actor)->orderBy('time')->lists('id'); // TODO: Refactor to be simpler, and get posts straight from the // discussion's postsVisibleTo relation method. if (in_array('posts', $request->include)) { $prefixLength = strlen($prefix = 'posts.'); $postRelations = array_filter(array_map(function ($relation) use($prefix, $prefixLength) { return substr($relation, 0, $prefixLength) === $prefix ? substr($relation, $prefixLength) : false; }, $request->include)); $discussion->posts = $this->getPosts($request, ['discussion_id' => $discussion->id])->load($postRelations); } return $discussion; }
/** * @param PostReply $command * @return CommentPost * @throws \Flarum\Core\Exceptions\PermissionDeniedException */ public function handle(PostReply $command) { $actor = $command->actor; // Make sure the user has permission to reply to this discussion. First, // make sure the discussion exists and that the user has permission to // view it; if not, fail with a ModelNotFound exception so we don't give // away the existence of the discussion. If the user is allowed to view // it, check if they have permission to reply. $discussion = $this->discussions->findOrFail($command->discussionId, $actor); $discussion->assertCan($actor, 'reply'); // Create a new Post entity, persist it, and dispatch domain events. // Before persistence, though, fire an event to give plugins an // opportunity to alter the post entity based on data in the command. $post = CommentPost::reply($command->discussionId, array_get($command->data, 'attributes.content'), $actor->id); event(new PostWillBeSaved($post, $actor, $command->data)); $post->save(); $this->notifications->onePerUser(function () use($post) { $this->dispatchEventsFor($post); }); return $post; }