Skip to content

Commit

Permalink
+ classes BasePostKey, PostKeyWithParent, (Sub)?Reply & `Thread…
Browse files Browse the repository at this point in the history
…` @ `App\DTO\PostKey`

* replace `selectCurrentAndParentPostID()` to abstract `selectPostKeyDTO()` @ `App\Repository\Post\PostRepository`, also affects `App\PostsQuery\BaseQuery` & `App\PostsQuery\CursorCodec->encodeNextCursor()`

* move the selecting field `$this->orderByField` on query builder from `setResult()` to `App\Repository\Post\PostRepository->selectPostKeyDTO()`
* split variables `$(subR|r)eplies` by its twice assignments @ `fillWithParentPost()`
@ `BaseQuery`

* move the assign to `$this->orderByField` before the invoking to `App\Repository\Post\PostRepository->selectPostKeyDTO()` @ `(Index|Search)Query->query()`
@ `App\PostsQuery`
@ be
  • Loading branch information
n0099 committed Oct 13, 2024
1 parent e9b73bb commit f912317
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 51 deletions.
12 changes: 12 additions & 0 deletions be/src/DTO/PostKey/BasePostKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

Check warning on line 1 in be/src/DTO/PostKey/BasePostKey.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

BasePostKey.php: PHP-CS-Fixer.class_definition: Found violation(s) of type: class_definition

Check warning on line 1 in be/src/DTO/PostKey/BasePostKey.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

BasePostKey.php: PHP-CS-Fixer.braces_position: Found violation(s) of type: braces_position

Check warning on line 1 in be/src/DTO/PostKey/BasePostKey.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

BasePostKey.php: PHP-CS-Fixer.single_line_empty_body: Found violation(s) of type: single_line_empty_body

namespace App\DTO\PostKey;

readonly abstract class BasePostKey
{
public function __construct(
public int $postId,
public string $orderByFieldName,
public mixed $orderByFieldValue,
) {}
}
13 changes: 13 additions & 0 deletions be/src/DTO/PostKey/PostKeyWithParent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

Check warning on line 1 in be/src/DTO/PostKey/PostKeyWithParent.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

PostKeyWithParent.php: PHP-CS-Fixer.class_definition: Found violation(s) of type: class_definition

Check warning on line 1 in be/src/DTO/PostKey/PostKeyWithParent.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

PostKeyWithParent.php: PHP-CS-Fixer.braces_position: Found violation(s) of type: braces_position

Check warning on line 1 in be/src/DTO/PostKey/PostKeyWithParent.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

PostKeyWithParent.php: PHP-CS-Fixer.single_line_empty_body: Found violation(s) of type: single_line_empty_body

namespace App\DTO\PostKey;

readonly abstract class PostKeyWithParent extends BasePostKey
{
public function __construct(
public int $parentPostId,
public int $postId,
public string $orderByFieldName,
public mixed $orderByFieldValue,
) {}
}
7 changes: 7 additions & 0 deletions be/src/DTO/PostKey/Reply.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

Check warning on line 1 in be/src/DTO/PostKey/Reply.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

Reply.php: PHP-CS-Fixer.single_line_empty_body: Found violation(s) of type: single_line_empty_body

namespace App\DTO\PostKey;

readonly class Reply extends PostKeyWithParent
{
}
14 changes: 14 additions & 0 deletions be/src/DTO/PostKey/SubReply.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\DTO\PostKey;

readonly class SubReply extends PostKeyWithParent
{
public function __construct(
public int $tid,
public int $parentPostId,
public int $postId,
public string $orderByFieldName,
public mixed $orderByFieldValue,
) {}
}
7 changes: 7 additions & 0 deletions be/src/DTO/PostKey/Thread.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

Check warning on line 1 in be/src/DTO/PostKey/Thread.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / pint

Thread.php: PHP-CS-Fixer.single_line_empty_body: Found violation(s) of type: single_line_empty_body

namespace App\DTO\PostKey;

readonly class Thread extends BasePostKey
{
}
44 changes: 24 additions & 20 deletions be/src/PostsQuery/BaseQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace App\PostsQuery;

use App\DTO\PostKey\BasePostKey;
use App\Entity\Post\Content\ReplyContent;
use App\Entity\Post\Content\SubReplyContent;
use App\Entity\Post\Post;
use App\Entity\Post\Reply;
use App\Entity\Post\SubReply;
use App\Entity\Post\Thread;
use App\DTO\PostKey\Thread as ThreadKey;
use App\DTO\PostKey\Reply as ReplyKey;
use App\DTO\PostKey\SubReply as SubReplyKey;
use App\Helper;
use App\Repository\Post\PostRepositoryFactory;
use Doctrine\ORM\Query\Expr;
Expand All @@ -21,9 +24,9 @@ abstract class BaseQuery
{
/** @type array{
* fid: int,
* threads: ?Collection<int, Thread>,
* replies: ?Collection<int, Reply>,
* subReplies: ?Collection<int, SubReply>
* threads: ?Collection<int, ThreadKey>,
* replies: ?Collection<int, ReplyKey>,
* subReplies: ?Collection<int, SubReplyKey>
* }
*/
private array $queryResult;
Expand Down Expand Up @@ -65,9 +68,6 @@ protected function setResult(
$this->stopwatch->start('setResult');

$orderedQueries = $queries->map(fn(QueryBuilder $qb, string $postType): QueryBuilder => $qb
// we don't have to select the post ID
// since it's already selected by invokes of PostRepository->selectCurrentAndParentPostID()
->addSelect("t.$this->orderByField")
->addOrderBy("t.$this->orderByField", $this->orderByDesc === true ? 'DESC' : 'ASC')
// cursor paginator requires values of orderBy column are unique
// if not it should fall back to other unique field (here is the post ID primary key)
Expand Down Expand Up @@ -151,20 +151,19 @@ public function fillWithParentPost(): array
/** @var Collection<int, int> $tids */
/** @var Collection<int, int> $pids */
/** @var Collection<int, int> $spids */
/** @var Collection<int, Reply> $replies */
/** @var Collection<int, SubReply> $subReplies */
[[, $tids], [$replies, $pids], [$subReplies, $spids]] = array_map(
/**
* @param string $postIDName
* @return array{0: Collection<int, Post>, 1: Collection<int, int>}
*/
static function (string $postIDName) use ($result): array {
$postTypePluralName = Helper::POST_ID_TO_TYPE_PLURAL[$postIDName];
/** @var Collection<int, ReplyKey> $replyKeys */
/** @var Collection<int, SubReplyKey> $subReplyKeys */
[[, $tids], [$replyKeys, $pids], [$subReplyKeys, $spids]] = array_map(
/** @return array{0: Collection<int, BasePostKey>, 1: Collection<int, int>} */
static function (string $postTypePluralName) use ($result): array {
return \array_key_exists($postTypePluralName, $result)
? [$result[$postTypePluralName], $result[$postTypePluralName]->pluck($postIDName)]
? [
$result[$postTypePluralName],
$result[$postTypePluralName]->map(fn(BasePostKey $postKey) => $postKey->postId)
]
: [collect(), collect()];
},
Helper::POST_ID,
Helper::POST_TYPES_PLURAL,
);

/** @var int $fid */
Expand All @@ -173,7 +172,10 @@ static function (string $postIDName) use ($result): array {

$this->stopwatch->start('fillWithThreadsFields');
/** @var Collection<int, int> $parentThreadsID parent tid of all replies and their sub replies */
$parentThreadsID = $replies->pluck('tid')->concat($subReplies->pluck('tid'))->unique();
$parentThreadsID = $replyKeys
->map(fn(ReplyKey $postKey) => $postKey->parentPostId)
->concat($subReplyKeys->map(fn(SubReplyKey $postKey) => $postKey->tid))
->unique();
/** @var Collection<int, Thread> $threads */
$threads = collect($postModels['thread']->getPosts($parentThreadsID->concat($tids)))
->each(static fn(Thread $thread) =>
Expand All @@ -182,14 +184,16 @@ static function (string $postIDName) use ($result): array {

$this->stopwatch->start('fillWithRepliesFields');
/** @var Collection<int, int> $parentRepliesID parent pid of all sub replies */
$parentRepliesID = $subReplies->pluck('pid')->unique();
$parentRepliesID = $subReplyKeys->map(fn(SubReplyKey $postKey) => $postKey->parentPostId)->unique();
$allRepliesId = $parentRepliesID->concat($pids);
/** @var Collection<int, Reply> $replies */
$replies = collect($postModels['reply']->getPosts($allRepliesId))
->each(static fn(Reply $reply) =>
$reply->setIsMatchQuery($pids->contains($reply->getPid())));
$this->stopwatch->stop('fillWithRepliesFields');

$this->stopwatch->start('fillWithSubRepliesFields');
/** @var Collection<int, SubReply> $subReplies */
$subReplies = collect($postModels['subReply']->getPosts($spids));
$this->stopwatch->stop('fillWithSubRepliesFields');

Expand Down
4 changes: 2 additions & 2 deletions be/src/PostsQuery/CursorCodec.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\PostsQuery;

use App\DTO\PostKey\BasePostKey;
use App\Helper;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
Expand All @@ -21,8 +22,7 @@ public function encodeNextCursor(Collection $postsKeyByTypePluralName, string $o
Helper::POST_TYPE_PLURAL_TO_SINGULAR[$type] => $posts->last(), // null when no posts
]) // [singularPostTypeName => lastPostInResult]
->filter() // remove post types that have no posts
->map(fn(array $post, string $typePluralName) =>
[$post[Helper::POST_TYPE_TO_ID[$typePluralName]], $post[$orderByField]])
->map(fn(BasePostKey $post) => [$post->postId, $post->orderByFieldValue])
->map(static fn(array $cursors) => collect($cursors)
->map(static function (int|string $cursor): string {
if ($cursor === 0) { // quick exit to keep 0 as is
Expand Down
21 changes: 10 additions & 11 deletions be/src/PostsQuery/IndexQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,23 @@ public function query(QueryParams $params, ?string $cursor): void
/** @var array<string> $postTypes */
$postTypes = $flatParams['postTypes'];

if ($flatParams['orderBy'] === 'default') {
$this->orderByField = 'postedAt'; // order by postedAt to prevent posts out of order when order by post ID
if (\array_key_exists('fid', $flatParams) && $postIDParam->count() === 0) { // query by fid only
$this->orderByDesc = true;
} elseif ($hasPostIDParam) { // query by post ID (with or without fid)
$this->orderByDesc = false;
}
}

/**
* @param int $fid
* @return Collection<string, PostRepository> key by post type
*/
$getQueryBuilders = fn(int $fid): Collection =>
collect($this->postRepositoryFactory->newForumPosts($fid))
->only($postTypes)
->transform(static fn(PostRepository $repository) => $repository->selectCurrentAndParentPostID());
->transform(fn(PostRepository $repository) => $repository->selectPostKeyDTO($this->orderByField));
$getFidByPostIDParam = function (string $postIDName, int $postID): int {
$postExistencesKeyByFid = collect($this->forumRepository->getOrderedForumsId())
->mapWithKeys(fn(int $fid) => [$fid => $this->postRepositoryFactory
Expand Down Expand Up @@ -88,20 +97,10 @@ public function query(QueryParams $params, ?string $cursor): void
$qb->where("t.$postIDParamName = :postIDParamValue")
->setParameter('postIDParamValue', $postIDParamValue));
}

if (array_diff($postTypes, Helper::POST_TYPES) !== []) {
$queries = $queries->only($postTypes);
}

if ($flatParams['orderBy'] === 'default') {
$this->orderByField = 'postedAt'; // order by postedAt to prevent posts out of order when order by post ID
if (\array_key_exists('fid', $flatParams) && $postIDParam->count() === 0) { // query by fid only
$this->orderByDesc = true;
} elseif ($hasPostIDParam) { // query by post ID (with or without fid)
$this->orderByDesc = false;
}
}

$this->setResult($fid, $queries, $cursor, $hasPostIDParam ? $postIDParamName : null);
}
}
19 changes: 10 additions & 9 deletions be/src/PostsQuery/SearchQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,22 @@ public function query(QueryParams $params, ?string $cursor): void
{
/** @var int $fid */
$fid = $params->getUniqueParamValue('fid');

$orderByParam = $params->pick('orderBy')[0];
$this->orderByField = $orderByParam->value;
$this->orderByDesc = $orderByParam->getSub('direction');
if ($this->orderByField === 'default') {
$this->orderByField = 'postedAt';
$this->orderByDesc = true;
}

/** @var array<string, array> $cachedUserQueryResult key by param name */
$cachedUserQueryResult = [];
/** @var Collection<string, QueryBuilder> $queries key by post type */
$queries = collect($this->postRepositoryFactory->newForumPosts($fid))
->only($params->getUniqueParamValue('postTypes'))
->map(function (PostRepository $repository) use ($params, &$cachedUserQueryResult): QueryBuilder {
$postQuery = $repository->selectCurrentAndParentPostID();
$postQuery = $repository->selectPostKeyDTO($this->orderByField);
foreach ($params->omit() as $paramIndex => $param) { // omit nothing to get all params
// even when $cachedUserQueryResult[$param->name] is null
// it will still pass as a reference to the array item
Expand All @@ -47,14 +56,6 @@ public function query(QueryParams $params, ?string $cursor): void
return $postQuery;
});

$orderByParam = $params->pick('orderBy')[0];
$this->orderByField = $orderByParam->value;
$this->orderByDesc = $orderByParam->getSub('direction');
if ($this->orderByField === 'default') {
$this->orderByField = 'postedAt';
$this->orderByDesc = true;
}

$this->setResult($fid, $queries, $cursor);
}

Expand Down
10 changes: 1 addition & 9 deletions be/src/Repository/Post/PostRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Repository\Post;

use App\Entity\Post\Post;
use App\Helper;
use App\Repository\RepositoryWithSplitFid;
use Doctrine\ORM\QueryBuilder;

Expand All @@ -13,14 +12,7 @@
*/
abstract class PostRepository extends RepositoryWithSplitFid
{
public function selectCurrentAndParentPostID(): QueryBuilder
{
return $this->createQueryBuilder('t')->select(collect(Helper::POST_TYPE_TO_ID)
->slice(0, array_search($this->getTableNameSuffix(), Helper::POST_TYPES, true) + 1)
->values()
->map(static fn(string $postIDField) => "t.$postIDField")
->all());
}
abstract public function selectPostKeyDTO(string $orderByField): QueryBuilder;

abstract public function getPosts(array|\ArrayAccess $postsId): array;

Expand Down
8 changes: 8 additions & 0 deletions be/src/Repository/Post/ReplyRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace App\Repository\Post;

use App\DTO\PostKey\Reply as ReplyKey;
use App\Entity\Post\Reply;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\DependencyInjection\Attribute\Exclude;

Expand All @@ -21,6 +23,12 @@ protected function getTableNameSuffix(): string
return 'reply';
}

public function selectPostKeyDTO(string $orderByField): QueryBuilder
{
return $this->createQueryBuilder('t')
->select('new ' . ReplyKey::class . "(t.tid, t.pid, '$orderByField', t.$orderByField)");
}

public function getPosts(array|\ArrayAccess $postsId): array
{
$dql = 'SELECT t FROM App\Entity\Post\Reply t WHERE t.pid IN (:pid)';
Expand Down
8 changes: 8 additions & 0 deletions be/src/Repository/Post/SubReplyRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace App\Repository\Post;

use App\DTO\PostKey\SubReply as SubReplyKey;
use App\Entity\Post\SubReply;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\DependencyInjection\Attribute\Exclude;

Expand All @@ -21,6 +23,12 @@ protected function getTableNameSuffix(): string
return 'subReply';
}

public function selectPostKeyDTO(string $orderByField): QueryBuilder
{
return $this->createQueryBuilder('t')
->select('new ' . SubReplyKey::class . "(t.tid, t.pid, t.spid, '$orderByField', t.$orderByField)");
}

public function getPosts(array|\ArrayAccess $postsId): array
{
$dql = 'SELECT t FROM App\Entity\Post\SubReply t WHERE t.spid IN (:spid)';
Expand Down
8 changes: 8 additions & 0 deletions be/src/Repository/Post/ThreadRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace App\Repository\Post;

use App\DTO\PostKey\Thread as ThreadKey;
use App\Entity\Post\Thread;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\DependencyInjection\Attribute\Exclude;

Expand All @@ -21,6 +23,12 @@ protected function getTableNameSuffix(): string
return 'thread';
}

public function selectPostKeyDTO(string $orderByField): QueryBuilder
{
return $this->createQueryBuilder('t')
->select('new ' . ThreadKey::class . "(t.tid, '$orderByField', t.$orderByField)");
}

public function getPosts(array|\ArrayAccess $postsId): array
{
$dql = 'SELECT t FROM App\Entity\Post\Thread t WHERE t.tid IN (:tid)';
Expand Down

0 comments on commit f912317

Please sign in to comment.