| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Entities\Tools; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  | use BookStack\Actions\Tag; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Book; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Chapter; | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  | use BookStack\Entities\Models\Entity; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Page; | 
					
						
							| 
									
										
										
										
											2021-12-20 03:20:31 +08:00
										 |  |  | use BookStack\Entities\Repos\BookRepo; | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  | use BookStack\Entities\Repos\ChapterRepo; | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  | use BookStack\Entities\Repos\PageRepo; | 
					
						
							| 
									
										
										
										
											2021-12-20 03:20:31 +08:00
										 |  |  | use BookStack\Uploads\Image; | 
					
						
							|  |  |  | use BookStack\Uploads\ImageService; | 
					
						
							|  |  |  | use Illuminate\Http\UploadedFile; | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Cloner | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var PageRepo | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $pageRepo; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @var ChapterRepo | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $chapterRepo; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-20 03:20:31 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @var BookRepo | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $bookRepo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var ImageService | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $imageService; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo, BookRepo $bookRepo, ImageService $imageService) | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $this->pageRepo = $pageRepo; | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |         $this->chapterRepo = $chapterRepo; | 
					
						
							| 
									
										
										
										
											2021-12-20 03:20:31 +08:00
										 |  |  |         $this->bookRepo = $bookRepo; | 
					
						
							|  |  |  |         $this->imageService = $imageService; | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Clone the given page into the given parent using the provided name. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function clonePage(Page $original, Entity $parent, string $newName): Page | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $copyPage = $this->pageRepo->getNewDraftPage($parent); | 
					
						
							|  |  |  |         $pageData = $original->getAttributes(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |         // Update name & tags
 | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  |         $pageData['name'] = $newName; | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |         $pageData['tags'] = $this->entityTagsToInputArray($original); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this->pageRepo->publishDraft($copyPage, $pageData); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Clone the given page into the given parent using the provided name. | 
					
						
							|  |  |  |      * Clones all child pages. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function cloneChapter(Chapter $original, Book $parent, string $newName): Chapter | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $chapterDetails = $original->getAttributes(); | 
					
						
							|  |  |  |         $chapterDetails['name'] = $newName; | 
					
						
							|  |  |  |         $chapterDetails['tags'] = $this->entityTagsToInputArray($original); | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |         $copyChapter = $this->chapterRepo->create($chapterDetails, $parent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (userCan('page-create', $copyChapter)) { | 
					
						
							|  |  |  |             /** @var Page $page */ | 
					
						
							|  |  |  |             foreach ($original->getVisiblePages() as $page) { | 
					
						
							|  |  |  |                 $this->clonePage($page, $copyChapter, $page->name); | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |         return $copyChapter; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-20 03:20:31 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Clone the given book. | 
					
						
							|  |  |  |      * Clones all child chapters & pages. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function cloneBook(Book $original, string $newName): Book | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $bookDetails = $original->getAttributes(); | 
					
						
							|  |  |  |         $bookDetails['name'] = $newName; | 
					
						
							|  |  |  |         $bookDetails['tags'] = $this->entityTagsToInputArray($original); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $copyBook = $this->bookRepo->create($bookDetails); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $directChildren = $original->getDirectChildren(); | 
					
						
							|  |  |  |         foreach ($directChildren as $child) { | 
					
						
							|  |  |  |             if ($child instanceof Chapter && userCan('chapter-create', $copyBook)) { | 
					
						
							|  |  |  |                 $this->cloneChapter($child, $copyBook, $child->name); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if ($child instanceof Page && !$child->draft && userCan('page-create', $copyBook)) { | 
					
						
							|  |  |  |                 $this->clonePage($child, $copyBook, $child->name); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ($original->cover) { | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 $tmpImgFile = tmpfile(); | 
					
						
							|  |  |  |                 $uploadedFile = $this->imageToUploadedFile($original->cover, $tmpImgFile); | 
					
						
							|  |  |  |                 $this->bookRepo->updateCoverImage($copyBook, $uploadedFile, false); | 
					
						
							|  |  |  |             } catch (\Exception $exception) { | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $copyBook; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Convert an image instance to an UploadedFile instance to mimic | 
					
						
							|  |  |  |      * a file being uploaded. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function imageToUploadedFile(Image $image, &$tmpFile): ?UploadedFile | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $imgData = $this->imageService->getImageData($image); | 
					
						
							|  |  |  |         $tmpImgFilePath = stream_get_meta_data($tmpFile)['uri']; | 
					
						
							|  |  |  |         file_put_contents($tmpImgFilePath, $imgData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return new UploadedFile($tmpImgFilePath, basename($image->path)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-19 23:40:52 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Convert the tags on the given entity to the raw format | 
					
						
							|  |  |  |      * that's used for incoming request data. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function entityTagsToInputArray(Entity $entity): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $tags = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @var Tag $tag */ | 
					
						
							|  |  |  |         foreach ($entity->tags as $tag) { | 
					
						
							|  |  |  |             $tags[] = ['name' => $tag->name, 'value' => $tag->value]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $tags; | 
					
						
							| 
									
										
										
										
											2021-12-19 20:56:27 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-21 01:40:27 +08:00
										 |  |  | } |