Switched page lookup to use this.
use BookStack\Entities\Tools\PageEditActivity;
use BookStack\Entities\Tools\PageEditorData;
use BookStack\Exceptions\NotFoundException;
-use BookStack\Exceptions\NotifyException;
use BookStack\Exceptions\PermissionsException;
use BookStack\Http\Controller;
use BookStack\Permissions\Permission;
try {
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
} catch (NotFoundException $e) {
- $revision = $this->entityQueries->revisions->findLatestVersionBySlugs($bookSlug, $pageSlug);
- $page = $revision->page ?? null;
-
+ $page = $this->entityQueries->findVisibleByOldSlugs('page', $pageSlug, $bookSlug);
if (is_null($page)) {
throw $e;
}
--- /dev/null
+<?php
+
+namespace BookStack\Entities\Models;
+
+use BookStack\App\Model;
+use BookStack\Permissions\Models\JointPermission;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+/**
+ * @property int $id
+ * @property int $sluggable_id
+ * @property string $sluggable_type
+ * @property string $slug
+ * @property ?string $parent_slug
+ */
+class SlugHistory extends Model
+{
+ protected $table = 'slug_history';
+
+ public function jointPermissions(): HasMany
+ {
+ return $this->hasMany(JointPermission::class, 'entity_id', 'sluggable_id')
+ ->whereColumn('joint_permissions.entity_type', '=', 'slug_history.sluggable_type');
+ }
+}
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\EntityTable;
+use BookStack\Entities\Tools\SlugHistory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\JoinClause;
public ChapterQueries $chapters,
public PageQueries $pages,
public PageRevisionQueries $revisions,
+ protected SlugHistory $slugHistory,
) {
}
$explodedId = explode(':', $identifier);
$entityType = $explodedId[0];
$entityId = intval($explodedId[1]);
- $queries = $this->getQueriesForType($entityType);
- return $queries->findVisibleById($entityId);
+ return $this->findVisibleById($entityType, $entityId);
+ }
+
+ /**
+ * Find an entity by its ID.
+ */
+ public function findVisibleById(string $type, int $id): ?Entity
+ {
+ $queries = $this->getQueriesForType($type);
+ return $queries->findVisibleById($id);
+ }
+
+ /**
+ * Find an entity by looking up old slugs in the slug history.
+ */
+ public function findVisibleByOldSlugs(string $type, string $slug, string $parentSlug = ''): ?Entity
+ {
+ $id = $this->slugHistory->lookupEntityIdUsingSlugs($type, $slug, $parentSlug);
+ if ($id === null) {
+ return null;
+ }
+
+ return $this->findVisibleById($type, $id);
}
/**
use BookStack\Entities\Models\BookChild;
use BookStack\Entities\Models\Entity;
-use Illuminate\Support\Facades\DB;
+use BookStack\Entities\Models\SlugHistory as SlugHistoryModel;
+use BookStack\Permissions\PermissionApplicator;
class SlugHistory
{
+ public function __construct(
+ protected PermissionApplicator $permissions,
+ ) {
+ }
+
/**
* Record the current slugs for the given entity.
*/
return;
}
- $latest = $this->getLatestEntryForEntity($entity);
- if ($latest && $latest->slug === $entity->slug && $latest->parent_slug === $entity->getParent()?->slug) {
- return;
- }
-
$parentSlug = null;
if ($entity instanceof BookChild) {
$parentSlug = $entity->book()->first()?->slug;
}
+ $latest = $this->getLatestEntryForEntity($entity);
+ if ($latest && $latest->slug === $entity->slug && $latest->parent_slug === $parentSlug) {
+ return;
+ }
+
$info = [
'sluggable_type' => $entity->getMorphClass(),
'sluggable_id' => $entity->id,
'slug' => $entity->slug,
'parent_slug' => $parentSlug,
- 'created_at' => now(),
- 'updated_at' => now(),
];
- DB::table('slug_history')->insert($info);
+ $entry = new SlugHistoryModel();
+ $entry->forceFill($info);
+ $entry->save();
+ }
+
+ /**
+ * Find the latest visible entry for an entity which uses the given slug(s) in the history.
+ */
+ public function lookupEntityIdUsingSlugs(string $type, string $slug, string $parentSlug = ''): ?int
+ {
+ $query = SlugHistoryModel::query()
+ ->where('sluggable_type', '=', $type)
+ ->where('slug', '=', $slug);
+
+ if ($parentSlug) {
+ $query->where('parent_slug', '=', $parentSlug);
+ }
+
+ $query = $this->permissions->restrictEntityRelationQuery($query, 'slug_history', 'sluggable_id', 'sluggable_type');
+
+ /** @var SlugHistoryModel|null $result */
+ $result = $query->orderBy('created_at', 'desc')->first();
+
+ return $result?->sluggable_id;
}
- protected function getLatestEntryForEntity(Entity $entity): \stdClass|null
+ protected function getLatestEntryForEntity(Entity $entity): SlugHistoryModel|null
{
- return DB::table('slug_history')
+ return SlugHistoryModel::query()
->where('sluggable_type', '=', $entity->getMorphClass())
->where('sluggable_id', '=', $entity->id)
->orderBy('created_at', 'desc')