Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit 176c3bb

Browse files
committed
tag queries for and, or and not operators
1 parent 01f8047 commit 176c3bb

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

app/Services/PluginServices/QueryPluginsService.php

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,40 @@
44

55
use App\Models\WpOrg\Plugin;
66
use App\Utils\Regex;
7-
use App\Values\WpOrg\Plugins as PluginDTOs;
7+
use App\Values\WpOrg\Plugins;
88
use Illuminate\Database\Eloquent\Builder;
99

1010
class QueryPluginsService
1111
{
12-
public function queryPlugins(Plugins\QueryPluginsDTO $req): Plugins\QueryPluginsResponse
12+
public function queryPlugins(Plugins\QueryPluginsRequest $req): Plugins\QueryPluginsResponse
1313
{
14-
$page = $req->page;
14+
$page = $req->page;
1515
$perPage = $req->per_page;
16-
$browse = $req->browse ?: 'popular';
17-
$search = $req->search ?? null;
18-
$tags = $req->tags ?? [];
19-
$author = $req->author ?? null;
16+
$browse = $req->browse ?: 'popular';
17+
$search = $req->search ?? null;
18+
$author = $req->author ?? null;
19+
20+
// Operators coming from the DTO
21+
$tags = $req->tags ?? [];
22+
$tagAnd = $req->tagAnd ?? [];
23+
$tagOr = $req->tagOr ?? [];
24+
$tagNot = $req->tagNot ?? [];
25+
26+
// merge base tags with tagOr
27+
$anyTags = array_values(array_unique([...$tags, ...$tagOr]));
2028

2129
// Ad hoc pipeline because Laravel's Pipeline class is awful
2230
$callbacks = collect();
23-
$search and $callbacks->push(fn($query) => self::applySearchWeighted($query, $search, $req));
24-
$tags and $callbacks->push(fn($query) => self::applyTag($query, $tags));
25-
$author and $callbacks->push(fn($query) => self::applyAuthor($query, $author));
26-
!$search and $callbacks->push(fn($query) => self::applyBrowse($query, $browse)); // search applies its own sort
2731

32+
!empty($anyTags) && $callbacks->push(fn($q) => self::applyTagAny($q, $anyTags));
33+
!empty($tagAnd) && $callbacks->push(fn($q) => self::applyTagAll($q, $tagAnd));
34+
!empty($tagNot) && $callbacks->push(fn($q) => self::applyTagNot($q, $tagNot));
35+
36+
$search && $callbacks->push(fn($q) => self::applySearchWeighted($q, $search, $req));
37+
$author && $callbacks->push(fn($q) => self::applyAuthor($q, $author));
38+
!$search && $callbacks->push(fn($q) => self::applyBrowse($q, $browse));
39+
/** @var Builder<Plugin> $query */
2840
$query = $callbacks->reduce(fn($query, $callback) => $callback($query), Plugin::query());
29-
assert($query instanceof Builder);
3041

3142
$total = $query->count();
3243
$totalPages = (int)ceil($total / $perPage);
@@ -51,7 +62,11 @@ public function queryPlugins(Plugins\QueryPluginsDTO $req): Plugins\QueryPlugins
5162
* @param Builder<Plugin> $query
5263
* @return Builder<Plugin> Returns a new query with weighted search applied
5364
*/
54-
public static function applySearchWeighted(Builder $query, string $search, Plugins\QueryPluginsDTO $request): Builder
65+
public static function applySearchWeighted(
66+
Builder $query,
67+
string $search,
68+
Plugins\QueryPluginsRequest $request
69+
): Builder
5570
{
5671
$lcsearch = mb_strtolower($search);
5772
$slug = Regex::replace('/[^-\w]+/', '-', $lcsearch);
@@ -107,11 +122,28 @@ public static function applyAuthor(Builder $query, string $author): Builder
107122
}
108123

109124
/** @param Builder<Plugin> $query */
110-
public static function applyTag(Builder $query, array $tags): Builder
125+
public static function applyTagAny(Builder $query, array $tags): Builder
111126
{
112127
return $query->whereHas('tags', fn(Builder $q) => $q->whereIn('slug', $tags));
113128
}
114129

130+
/** @param Builder<Plugin> $query */
131+
public static function applyTagAll(Builder $query, array $tags): Builder
132+
{
133+
return $query->whereHas(
134+
'tags',
135+
fn(Builder $q) => $q->whereIn('slug', $tags),
136+
'>=',
137+
count($tags)
138+
);
139+
}
140+
141+
/** @param Builder<Plugin> $query */
142+
public static function applyTagNot(Builder $query, array $slugs): Builder
143+
{
144+
return $query->whereDoesntHave('tags', fn(Builder $q) => $q->whereIn('slug', $slugs));
145+
}
146+
115147
/**
116148
* Apply sorting based on browse parameter
117149
*

0 commit comments

Comments
 (0)