| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Entities\Tools; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use BookStack\App\Model; | 
					
						
							| 
									
										
										
										
											2024-02-09 00:39:59 +08:00
										 |  |  | use BookStack\Entities\Queries\EntityQueries; | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  | use Illuminate\Database\Eloquent\Relations\Relation; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MixedEntityListLoader | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     public function __construct( | 
					
						
							| 
									
										
										
										
											2024-02-09 00:39:59 +08:00
										 |  |  |         protected EntityQueries $queries, | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  |     ) { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Efficiently load in entities for listing onto the given list | 
					
						
							|  |  |  |      * where entities are set as a relation via the given name. | 
					
						
							|  |  |  |      * This will look for a model id and type via 'name_id' and 'name_type'. | 
					
						
							|  |  |  |      * @param Model[] $relations | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2024-02-04 22:39:01 +08:00
										 |  |  |     public function loadIntoRelations(array $relations, string $relationName, bool $loadParents): void | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $idsByType = []; | 
					
						
							|  |  |  |         foreach ($relations as $relation) { | 
					
						
							|  |  |  |             $type = $relation->getAttribute($relationName . '_type'); | 
					
						
							|  |  |  |             $id = $relation->getAttribute($relationName . '_id'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!isset($idsByType[$type])) { | 
					
						
							|  |  |  |                 $idsByType[$type] = []; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $idsByType[$type][] = $id; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-04 22:39:01 +08:00
										 |  |  |         $modelMap = $this->idsByTypeToModelMap($idsByType, $loadParents); | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         foreach ($relations as $relation) { | 
					
						
							|  |  |  |             $type = $relation->getAttribute($relationName . '_type'); | 
					
						
							|  |  |  |             $id = $relation->getAttribute($relationName . '_id'); | 
					
						
							|  |  |  |             $related = $modelMap[$type][strval($id)] ?? null; | 
					
						
							|  |  |  |             if ($related) { | 
					
						
							|  |  |  |                 $relation->setRelation($relationName, $related); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param array<string, int[]> $idsByType | 
					
						
							|  |  |  |      * @return array<string, array<int, Model>> | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2024-02-04 22:39:01 +08:00
										 |  |  |     protected function idsByTypeToModelMap(array $idsByType, bool $eagerLoadParents): array | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $modelMap = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($idsByType as $type => $ids) { | 
					
						
							| 
									
										
										
										
											2024-02-09 00:39:59 +08:00
										 |  |  |             $models = $this->queries->visibleForList($type) | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  |                 ->whereIn('id', $ids) | 
					
						
							| 
									
										
										
										
											2024-02-04 22:39:01 +08:00
										 |  |  |                 ->with($eagerLoadParents ? $this->getRelationsToEagerLoad($type) : []) | 
					
						
							| 
									
										
										
										
											2023-12-19 00:23:40 +08:00
										 |  |  |                 ->get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (count($models) > 0) { | 
					
						
							|  |  |  |                 $modelMap[$type] = []; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             foreach ($models as $model) { | 
					
						
							|  |  |  |                 $modelMap[$type][strval($model->id)] = $model; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $modelMap; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function getRelationsToEagerLoad(string $type): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $toLoad = []; | 
					
						
							|  |  |  |         $loadVisible = fn (Relation $query) => $query->scopes('visible'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ($type === 'chapter' || $type === 'page') { | 
					
						
							|  |  |  |             $toLoad['book'] = $loadVisible; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ($type === 'page') { | 
					
						
							|  |  |  |             $toLoad['chapter'] = $loadVisible; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $toLoad; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |