3 namespace BookStack\Entities\Tools;
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\BookChild;
7 use BookStack\Entities\Models\Entity;
8 use BookStack\Entities\Models\EntityTable;
9 use BookStack\Entities\Models\SlugHistory as SlugHistoryModel;
10 use BookStack\Permissions\PermissionApplicator;
11 use Illuminate\Support\Facades\DB;
15 public function __construct(
16 protected PermissionApplicator $permissions,
21 * Record the current slugs for the given entity.
23 public function recordForEntity(Entity $entity): void
25 if (!$entity->id || !$entity->slug) {
30 if ($entity instanceof BookChild) {
31 $parentSlug = $entity->book()->first()?->slug;
34 $latest = $this->getLatestEntryForEntity($entity);
35 if ($latest && $latest->slug === $entity->slug && $latest->parent_slug === $parentSlug) {
40 'sluggable_type' => $entity->getMorphClass(),
41 'sluggable_id' => $entity->id,
42 'slug' => $entity->slug,
43 'parent_slug' => $parentSlug,
46 $entry = new SlugHistoryModel();
47 $entry->forceFill($info);
50 if ($entity instanceof Book) {
51 $this->recordForBookChildren($entity);
55 protected function recordForBookChildren(Book $book): void
57 $query = EntityTable::query()
58 ->select(['type', 'id', 'slug', DB::raw("'{$book->slug}' as parent_slug"), DB::raw('now() as created_at'), DB::raw('now() as updated_at')])
59 ->where('book_id', '=', $book->id)
60 ->whereNotNull('book_id');
62 SlugHistoryModel::query()->insertUsing(
63 ['sluggable_type', 'sluggable_id', 'slug', 'parent_slug', 'created_at', 'updated_at'],
69 * Find the latest visible entry for an entity which uses the given slug(s) in the history.
71 public function lookupEntityIdUsingSlugs(string $type, string $slug, string $parentSlug = ''): ?int
73 $query = SlugHistoryModel::query()
74 ->where('sluggable_type', '=', $type)
75 ->where('slug', '=', $slug);
78 $query->where('parent_slug', '=', $parentSlug);
81 $query = $this->permissions->restrictEntityRelationQuery($query, 'slug_history', 'sluggable_id', 'sluggable_type');
83 /** @var SlugHistoryModel|null $result */
84 $result = $query->orderBy('created_at', 'desc')->first();
86 return $result?->sluggable_id;
89 protected function getLatestEntryForEntity(Entity $entity): SlugHistoryModel|null
91 return SlugHistoryModel::query()
92 ->where('sluggable_type', '=', $entity->getMorphClass())
93 ->where('sluggable_id', '=', $entity->id)
94 ->orderBy('created_at', 'desc')