44
55use App \Models \WpOrg \Plugin ;
66use App \Utils \Regex ;
7- use App \Values \WpOrg \Plugins as PluginDTOs ;
7+ use App \Values \WpOrg \Plugins ;
88use Illuminate \Database \Eloquent \Builder ;
99
1010class 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