]> BookStack Code Mirror - bookstack/blob - app/Entities/Tools/MixedEntityListLoader.php
Vectors: Added command to regenerate for all
[bookstack] / app / Entities / Tools / MixedEntityListLoader.php
1 <?php
2
3 namespace BookStack\Entities\Tools;
4
5 use BookStack\App\Model;
6 use BookStack\Entities\Queries\EntityQueries;
7 use Illuminate\Database\Eloquent\Relations\Relation;
8
9 class MixedEntityListLoader
10 {
11     public function __construct(
12         protected EntityQueries $queries,
13     ) {
14     }
15
16     /**
17      * Efficiently load in entities for listing onto the given list
18      * where entities are set as a relation via the given name.
19      * This will look for a model id and type via 'name_id' and 'name_type'.
20      * @param Model[] $relations
21      */
22     public function loadIntoRelations(array $relations, string $relationName, bool $loadParents): void
23     {
24         $idsByType = [];
25         foreach ($relations as $relation) {
26             $type = $relation->getAttribute($relationName . '_type');
27             $id = $relation->getAttribute($relationName . '_id');
28
29             if (!isset($idsByType[$type])) {
30                 $idsByType[$type] = [];
31             }
32
33             $idsByType[$type][] = $id;
34         }
35
36         $modelMap = $this->idsByTypeToModelMap($idsByType, $loadParents);
37
38         foreach ($relations as $relation) {
39             $type = $relation->getAttribute($relationName . '_type');
40             $id = $relation->getAttribute($relationName . '_id');
41             $related = $modelMap[$type][strval($id)] ?? null;
42             if ($related) {
43                 $relation->setRelation($relationName, $related);
44             }
45         }
46     }
47
48     /**
49      * @param array<string, int[]> $idsByType
50      * @return array<string, array<int, Model>>
51      */
52     protected function idsByTypeToModelMap(array $idsByType, bool $eagerLoadParents): array
53     {
54         $modelMap = [];
55
56         foreach ($idsByType as $type => $ids) {
57             $models = $this->queries->visibleForList($type)
58                 ->whereIn('id', $ids)
59                 ->with($eagerLoadParents ? $this->getRelationsToEagerLoad($type) : [])
60                 ->get();
61
62             if (count($models) > 0) {
63                 $modelMap[$type] = [];
64             }
65
66             foreach ($models as $model) {
67                 $modelMap[$type][strval($model->id)] = $model;
68             }
69         }
70
71         return $modelMap;
72     }
73
74     protected function getRelationsToEagerLoad(string $type): array
75     {
76         $toLoad = [];
77         $loadVisible = fn (Relation $query) => $query->scopes('visible');
78
79         if ($type === 'chapter' || $type === 'page') {
80             $toLoad['book'] = $loadVisible;
81         }
82
83         if ($type === 'page') {
84             $toLoad['chapter'] = $loadVisible;
85         }
86
87         return $toLoad;
88     }
89 }