| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | namespace BookStack\Activity; | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Activity\Models\Tag; | 
					
						
							| 
									
										
										
										
											2020-11-22 08:17:45 +08:00
										 |  |  | use BookStack\Entities\Models\Entity; | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Permissions\PermissionApplicator; | 
					
						
							| 
									
										
										
										
											2022-10-31 19:40:28 +08:00
										 |  |  | use BookStack\Util\SimpleListOptions; | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  | use Illuminate\Database\Eloquent\Builder; | 
					
						
							| 
									
										
										
										
											2020-06-30 05:11:03 +08:00
										 |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2021-09-26 22:48:22 +08:00
										 |  |  | use Illuminate\Support\Facades\DB; | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-14 04:20:21 +08:00
										 |  |  | class TagRepo | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-08 00:47:46 +08:00
										 |  |  |     public function __construct( | 
					
						
							|  |  |  |         protected PermissionApplicator $permissions | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |      * Start a query against all tags in the system. | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-10-31 19:40:28 +08:00
										 |  |  |     public function queryWithTotals(SimpleListOptions $listOptions, string $nameFilter): Builder | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-10-31 19:40:28 +08:00
										 |  |  |         $searchTerm = $listOptions->getSearch(); | 
					
						
							|  |  |  |         $sort = $listOptions->getSort(); | 
					
						
							|  |  |  |         if ($sort === 'name' && $nameFilter) { | 
					
						
							|  |  |  |             $sort = 'value'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |         $query = Tag::query() | 
					
						
							|  |  |  |             ->select([ | 
					
						
							|  |  |  |                 'name', | 
					
						
							|  |  |  |                 ($searchTerm || $nameFilter) ? 'value' : DB::raw('COUNT(distinct value) as `values`'), | 
					
						
							|  |  |  |                 DB::raw('COUNT(id) as usages'), | 
					
						
							| 
									
										
										
										
											2022-05-16 21:05:21 +08:00
										 |  |  |                 DB::raw('SUM(IF(entity_type = \'page\', 1, 0)) as page_count'), | 
					
						
							|  |  |  |                 DB::raw('SUM(IF(entity_type = \'chapter\', 1, 0)) as chapter_count'), | 
					
						
							|  |  |  |                 DB::raw('SUM(IF(entity_type = \'book\', 1, 0)) as book_count'), | 
					
						
							|  |  |  |                 DB::raw('SUM(IF(entity_type = \'bookshelf\', 1, 0)) as shelf_count'), | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |             ]) | 
					
						
							| 
									
										
										
										
											2024-04-16 01:44:59 +08:00
										 |  |  |             ->orderBy($sort, $listOptions->getOrder()) | 
					
						
							|  |  |  |             ->whereHas('entity'); | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ($nameFilter) { | 
					
						
							|  |  |  |             $query->where('name', '=', $nameFilter); | 
					
						
							| 
									
										
										
										
											2021-11-16 03:00:37 +08:00
										 |  |  |             $query->groupBy('value'); | 
					
						
							| 
									
										
										
										
											2021-11-16 20:29:50 +08:00
										 |  |  |         } elseif ($searchTerm) { | 
					
						
							| 
									
										
										
										
											2021-11-16 03:00:37 +08:00
										 |  |  |             $query->groupBy('name', 'value'); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             $query->groupBy('name'); | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ($searchTerm) { | 
					
						
							| 
									
										
										
										
											2021-11-07 06:00:33 +08:00
										 |  |  |             $query->where(function (Builder $query) use ($searchTerm) { | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |                 $query->where('name', 'like', '%' . $searchTerm . '%') | 
					
						
							|  |  |  |                     ->orWhere('value', 'like', '%' . $searchTerm . '%'); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-17 02:54:25 +08:00
										 |  |  |         return $this->permissions->restrictEntityRelationQuery($query, 'tags', 'entity_id', 'entity_type'); | 
					
						
							| 
									
										
										
										
											2016-05-07 03:33:08 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2016-05-14 04:20:21 +08:00
										 |  |  |      * Get tag name suggestions from scanning existing tag names. | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  |      * If no search term is given the 50 most popular tag names are provided. | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-09-28 20:50:40 +08:00
										 |  |  |     public function getNameSuggestions(string $searchTerm): Collection | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |         $query = Tag::query() | 
					
						
							| 
									
										
										
										
											2021-03-15 03:52:07 +08:00
										 |  |  |             ->select('*', DB::raw('count(*) as count')) | 
					
						
							|  |  |  |             ->groupBy('name'); | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ($searchTerm) { | 
					
						
							| 
									
										
										
										
											2022-09-28 20:50:40 +08:00
										 |  |  |             $query = $query->where('name', 'LIKE', $searchTerm . '%')->orderBy('name', 'asc'); | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             $query = $query->orderBy('count', 'desc')->take(50); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-17 02:54:25 +08:00
										 |  |  |         $query = $this->permissions->restrictEntityRelationQuery($query, 'tags', 'entity_id', 'entity_type'); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 20:50:40 +08:00
										 |  |  |         return $query->pluck('name'); | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-16 03:12:53 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Get tag value suggestions from scanning existing tag values. | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  |      * If no search is given the 50 most popular values are provided. | 
					
						
							|  |  |  |      * Passing a tagName will only find values for a tags with a particular name. | 
					
						
							| 
									
										
										
										
											2016-05-16 03:12:53 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-09-28 20:50:40 +08:00
										 |  |  |     public function getValueSuggestions(string $searchTerm, string $tagName): Collection | 
					
						
							| 
									
										
										
										
											2016-05-16 03:12:53 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |         $query = Tag::query() | 
					
						
							| 
									
										
										
										
											2021-03-15 03:52:07 +08:00
										 |  |  |             ->select('*', DB::raw('count(*) as count')) | 
					
						
							| 
									
										
										
										
											2023-04-08 00:47:46 +08:00
										 |  |  |             ->where('value', '!=', '') | 
					
						
							| 
									
										
										
										
											2021-03-15 03:52:07 +08:00
										 |  |  |             ->groupBy('value'); | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ($searchTerm) { | 
					
						
							|  |  |  |             $query = $query->where('value', 'LIKE', $searchTerm . '%')->orderBy('value', 'desc'); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             $query = $query->orderBy('count', 'desc')->take(50); | 
					
						
							| 
									
										
										
										
											2016-06-04 21:54:31 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 05:11:03 +08:00
										 |  |  |         if ($tagName) { | 
					
						
							| 
									
										
										
										
											2018-01-29 00:58:52 +08:00
										 |  |  |             $query = $query->where('name', '=', $tagName); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-17 02:54:25 +08:00
										 |  |  |         $query = $this->permissions->restrictEntityRelationQuery($query, 'tags', 'entity_id', 'entity_type'); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 20:50:40 +08:00
										 |  |  |         return $query->pluck('value'); | 
					
						
							| 
									
										
										
										
											2016-05-16 03:12:53 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-04 22:37:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * Save an array of tags to an entity. | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-06-30 05:11:03 +08:00
										 |  |  |     public function saveTagsToEntity(Entity $entity, array $tags = []): iterable | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-05-14 04:20:21 +08:00
										 |  |  |         $entity->tags()->delete(); | 
					
						
							| 
									
										
										
										
											2020-05-23 07:28:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 05:11:03 +08:00
										 |  |  |         $newTags = collect($tags)->filter(function ($tag) { | 
					
						
							|  |  |  |             return boolval(trim($tag['name'])); | 
					
						
							|  |  |  |         })->map(function ($tag) { | 
					
						
							|  |  |  |             return $this->newInstanceFromInput($tag); | 
					
						
							|  |  |  |         })->all(); | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-14 04:20:21 +08:00
										 |  |  |         return $entity->tags()->saveMany($newTags); | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2016-05-14 04:20:21 +08:00
										 |  |  |      * Create a new Tag instance from user input. | 
					
						
							| 
									
										
										
										
											2020-06-30 05:11:03 +08:00
										 |  |  |      * Input must be an array with a 'name' and an optional 'value' key. | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-06-30 05:11:03 +08:00
										 |  |  |     protected function newInstanceFromInput(array $input): Tag | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-11-07 00:30:20 +08:00
										 |  |  |         return new Tag([ | 
					
						
							|  |  |  |             'name'  => trim($input['name']), | 
					
						
							|  |  |  |             'value' => trim($input['value'] ?? ''), | 
					
						
							|  |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2016-05-07 21:29:43 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-01-29 00:58:52 +08:00
										 |  |  | } |