3 namespace BookStack\Entities\Repos;
5 use BookStack\Activity\TagRepo;
6 use BookStack\Entities\Models\BookChild;
7 use BookStack\Entities\Models\HasCoverInterface;
8 use BookStack\Entities\Models\HasDescriptionInterface;
9 use BookStack\Entities\Models\Entity;
10 use BookStack\Entities\Queries\PageQueries;
11 use BookStack\Entities\Tools\SlugGenerator;
12 use BookStack\Entities\Tools\SlugHistory;
13 use BookStack\Exceptions\ImageUploadException;
14 use BookStack\References\ReferenceStore;
15 use BookStack\References\ReferenceUpdater;
16 use BookStack\Sorting\BookSorter;
17 use BookStack\Uploads\ImageRepo;
18 use BookStack\Util\HtmlDescriptionFilter;
19 use Illuminate\Http\UploadedFile;
23 public function __construct(
24 protected TagRepo $tagRepo,
25 protected ImageRepo $imageRepo,
26 protected ReferenceUpdater $referenceUpdater,
27 protected ReferenceStore $referenceStore,
28 protected PageQueries $pageQueries,
29 protected BookSorter $bookSorter,
30 protected SlugGenerator $slugGenerator,
31 protected SlugHistory $slugHistory,
36 * Create a new entity in the system.
37 * @template T of Entity
41 public function create(Entity $entity, array $input): Entity
43 $entity = (clone $entity)->refresh();
44 $entity->fill($input);
46 'created_by' => user()->id,
47 'updated_by' => user()->id,
48 'owned_by' => user()->id,
50 $this->refreshSlug($entity);
52 if ($entity instanceof HasDescriptionInterface) {
53 $this->updateDescription($entity, $input);
58 if (isset($input['tags'])) {
59 $this->tagRepo->saveTagsToEntity($entity, $input['tags']);
63 $entity->rebuildPermissions();
64 $entity->indexForSearch();
66 $this->referenceStore->updateForEntity($entity);
72 * Update the given entity.
73 * @template T of Entity
77 public function update(Entity $entity, array $input): Entity
79 $oldUrl = $entity->getUrl();
81 $entity->fill($input);
82 $entity->updated_by = user()->id;
84 if ($entity->isDirty('name') || empty($entity->slug)) {
85 $this->refreshSlug($entity);
88 if ($entity instanceof HasDescriptionInterface) {
89 $this->updateDescription($entity, $input);
94 if (isset($input['tags'])) {
95 $this->tagRepo->saveTagsToEntity($entity, $input['tags']);
99 $entity->indexForSearch();
100 $this->referenceStore->updateForEntity($entity);
102 if ($oldUrl !== $entity->getUrl()) {
103 $this->referenceUpdater->updateEntityReferences($entity, $oldUrl);
110 * Update the given items' cover image or clear it.
112 * @throws ImageUploadException
115 public function updateCoverImage(Entity&HasCoverInterface $entity, ?UploadedFile $coverImage, bool $removeImage = false): void
118 $imageType = 'cover_' . $entity->type;
119 $this->imageRepo->destroyImage($entity->coverInfo()->getImage());
120 $image = $this->imageRepo->saveNew($coverImage, $imageType, $entity->id, 512, 512, true);
121 $entity->coverInfo()->setImage($image);
126 $this->imageRepo->destroyImage($entity->coverInfo()->getImage());
127 $entity->coverInfo()->setImage(null);
133 * Sort the parent of the given entity if any auto sort actions are set for it.
134 * Typically ran during create/update/insert events.
136 public function sortParent(Entity $entity): void
138 if ($entity instanceof BookChild) {
139 $book = $entity->book;
140 $this->bookSorter->runBookAutoSort($book);
145 * Update the description of the given entity from input data.
147 protected function updateDescription(Entity $entity, array $input): void
149 if (!$entity instanceof HasDescriptionInterface) {
153 if (isset($input['description_html'])) {
154 $entity->descriptionInfo()->set(
155 HtmlDescriptionFilter::filterFromString($input['description_html']),
156 html_entity_decode(strip_tags($input['description_html']))
158 } else if (isset($input['description'])) {
159 $entity->descriptionInfo()->set('', $input['description']);
164 * Refresh the slug for the given entity.
166 public function refreshSlug(Entity $entity): void
168 $this->slugHistory->recordForEntity($entity);
169 $this->slugGenerator->regenerateForEntity($entity);