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