]> BookStack Code Mirror - bookstack/blob - tests/Helpers/EntityProvider.php
d3888e71f66392b91f71a55192c71a6c2c2b90ba
[bookstack] / tests / Helpers / EntityProvider.php
1 <?php
2
3 namespace Tests\Helpers;
4
5 use BookStack\Auth\Role;
6 use BookStack\Auth\User;
7 use BookStack\Entities\Models\Book;
8 use BookStack\Entities\Models\Bookshelf;
9 use BookStack\Entities\Models\Chapter;
10 use BookStack\Entities\Models\Entity;
11 use BookStack\Entities\Models\Page;
12 use BookStack\Entities\Repos\BookRepo;
13 use BookStack\Entities\Repos\BookshelfRepo;
14 use BookStack\Entities\Repos\ChapterRepo;
15 use BookStack\Entities\Repos\PageRepo;
16
17 class EntityProvider
18 {
19     /**
20      * @var array<string, int[]>
21      */
22     protected array $fetchCache = [
23         'book' => [],
24         'page' => [],
25         'bookshelf' => [],
26         'chapter' => [],
27     ];
28
29     /**
30      * Get an un-fetched page from the system.
31      */
32     public function page(): Page
33     {
34         /** @var Page $page */
35         $page = Page::query()->whereNotIn('id', $this->fetchCache['page'])->first();
36         $this->addToCache($page);
37         return $page;
38     }
39
40     /**
41      * Get an un-fetched chapter from the system.
42      */
43     public function chapter(): Chapter
44     {
45         /** @var Chapter $chapter */
46         $chapter = Chapter::query()->whereNotIn('id', $this->fetchCache['chapter'])->first();
47         $this->addToCache($chapter);
48         return $chapter;
49     }
50
51     /**
52      * Get an un-fetched book from the system.
53      */
54     public function book(): Book
55     {
56         /** @var Book $book */
57         $book = Book::query()->whereNotIn('id', $this->fetchCache['book'])->first();
58         $this->addToCache($book);
59         return $book;
60     }
61
62     /**
63      * Get an un-fetched shelf from the system.
64      */
65     public function shelf(): Bookshelf
66     {
67         /** @var Bookshelf $shelf */
68         $shelf = Bookshelf::query()->whereNotIn('id', $this->fetchCache['bookshelf'])->first();
69         $this->addToCache($shelf);
70         return $shelf;
71     }
72
73     /**
74      * Get all entity types from the system.
75      * @return array{page: Page, chapter: Chapter, book: Book, bookshelf: Bookshelf}
76      */
77     public function all(): array
78     {
79         return [
80             'page'      => $this->page(),
81             'chapter'   => $this->chapter(),
82             'book'      => $this->book(),
83             'bookshelf' => $this->shelf(),
84         ];
85     }
86
87     /**
88      * Create a book to page chain of entities that belong to a specific user.
89      * @return array{book: Book, chapter: Chapter, page: Page}
90      */
91     public function createChainBelongingToUser(User $creatorUser, ?User $updaterUser = null): array
92     {
93         if (empty($updaterUser)) {
94             $updaterUser = $creatorUser;
95         }
96
97         $userAttrs = ['created_by' => $creatorUser->id, 'owned_by' => $creatorUser->id, 'updated_by' => $updaterUser->id];
98         /** @var Book $book */
99         $book = Book::factory()->create($userAttrs);
100         $chapter = Chapter::factory()->create(array_merge(['book_id' => $book->id], $userAttrs));
101         $page = Page::factory()->create(array_merge(['book_id' => $book->id, 'chapter_id' => $chapter->id], $userAttrs));
102
103         $book->rebuildPermissions();
104         $this->addToCache([$page, $chapter, $book]);
105
106         return compact('book', 'chapter', 'page');
107     }
108
109     /**
110      * Create and return a new bookshelf.
111      */
112     public function newShelf(array $input = ['name' => 'test shelf', 'description' => 'My new test shelf']): Bookshelf
113     {
114         $shelf = app(BookshelfRepo::class)->create($input, []);
115         $this->addToCache($shelf);
116         return $shelf;
117     }
118
119     /**
120      * Create and return a new book.
121      */
122     public function newBook(array $input = ['name' => 'test book', 'description' => 'My new test book']): Book
123     {
124         $book = app(BookRepo::class)->create($input);
125         $this->addToCache($book);
126         return $book;
127     }
128
129     /**
130      * Create and return a new test chapter.
131      */
132     public function newChapter(array $input, Book $book): Chapter
133     {
134         $chapter = app(ChapterRepo::class)->create($input, $book);
135         $this->addToCache($chapter);
136         return $chapter;
137     }
138
139     /**
140      * Create and return a new test page.
141      */
142     public function newPage(array $input = ['name' => 'test page', 'html' => 'My new test page']): Page
143     {
144         $book = Book::query()->first();
145         $pageRepo = app(PageRepo::class);
146         $draftPage = $pageRepo->getNewDraftPage($book);
147         $this->addToCache($draftPage);
148         return $pageRepo->publishDraft($draftPage, $input);
149     }
150
151     /**
152      * Regenerate the permission for an entity.
153      * Centralised to manage clearing of cached elements between requests.
154      */
155     public function regenPermissions(Entity $entity): void
156     {
157         $entity->rebuildPermissions();
158         $entity->load('jointPermissions');
159     }
160
161     /**
162      * Set the given entity as having restricted permissions, and apply the given
163      * permissions for the given roles.
164      * @param string[] $actions
165      * @param Role[] $roles
166      */
167     public function setPermissions(Entity $entity, array $actions = [], array $roles = []): void
168     {
169         $entity->restricted = true;
170         $entity->permissions()->delete();
171
172         $permissions = [];
173         foreach ($actions as $action) {
174             foreach ($roles as $role) {
175                 $permissions[] = [
176                     'role_id' => $role->id,
177                     'action'  => strtolower($action),
178                 ];
179             }
180         }
181
182         $entity->permissions()->createMany($permissions);
183         $entity->save();
184         $entity->load('permissions');
185         $this->regenPermissions($entity);
186     }
187
188     /**
189      * @param Entity|Entity[] $entities
190      */
191     protected function addToCache($entities): void
192     {
193         if (!is_array($entities)) {
194             $entities = [$entities];
195         }
196
197         foreach ($entities as $entity) {
198             $this->fetchCache[$entity->getType()][] = $entity->id;
199         }
200     }
201 }