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