public function build(
        stdClass $user,
        array $forums,
        array $discussions,
        array $posts
    ) : array {
        // Format the forums and discussion to make them more easily accessed later.
        $forums = array_reduce($forums, function($carry, $forum) {
            $carry[$forum->get_id()] = $forum;
            return $carry;
        }, []);
        $discussions = array_reduce($discussions, function($carry, $discussion) {
            $carry[$discussion->get_id()] = $discussion;
            return $carry;
        }, []);

        // Group the posts by discussion and forum so that we can load the resources in
        // batches to improve performance.
        $groupedposts = $this->group_posts_by_discussion($forums, $discussions, $posts);
        // Load all of the resources we need in order to export the posts.
        $authorsbyid = $this->get_authors_for_posts($posts);
        $authorcontextids = $this->get_author_context_ids(array_keys($authorsbyid));
        $attachmentsbypostid = $this->get_attachments_for_posts($groupedposts);
        $groupsbycourseandauthorid = $this->get_author_groups_from_posts($groupedposts);
        $tagsbypostid = $this->get_tags_from_posts($posts);
        $ratingbypostid = $this->get_ratings_from_posts($user, $groupedposts);
        $readreceiptcollectionbyforumid = $this->get_read_receipts_from_posts($user, $groupedposts);
        $exportedposts = [];

        // Export each set of posts per discussion because it's the largest chunks we can
        // break them into due to constraints on capability checks.
        foreach ($groupedposts as $grouping) {
            [
                'forum' => $forum,
                'discussion' => $discussion,
                'posts' => $groupedposts
            ] = $grouping;

            $forumid = $forum->get_id();
            $courseid = $forum->get_course_record()->id;
            $postsexporter = $this->exporterfactory->get_posts_exporter(
                $user,
                $forum,
                $discussion,
                $groupedposts,
                $authorsbyid,
                $authorcontextids,
                $attachmentsbypostid,
                $groupsbycourseandauthorid[$courseid],
                $readreceiptcollectionbyforumid[$forumid] ?? null,
                $tagsbypostid,
                $ratingbypostid,
                true
            );
            ['posts' => $exportedgroupedposts] = (array) $postsexporter->export($this->renderer);
            $exportedposts = array_merge($exportedposts, $exportedgroupedposts);
        }

        if (count($forums) == 1 && count($discussions) == 1) {
            // All of the posts belong to a single discussion in a single forum so
            // the exported order will match the given $posts array.
            return $exportedposts;
        } else {
            // Since we grouped the posts by discussion and forum the ordering of the
            // exported posts may be different to the given $posts array so we should
            // sort it back into the correct order for the caller.
            return $this->sort_exported_posts($posts, $exportedposts);
        }
    }