]> BookStack Code Mirror - bookstack/blob - app/Entities/Models/Page.php
Merge pull request #5919 from BookStackApp/v25-11
[bookstack] / app / Entities / Models / Page.php
1 <?php
2
3 namespace BookStack\Entities\Models;
4
5 use BookStack\Entities\Tools\PageContent;
6 use BookStack\Permissions\PermissionApplicator;
7 use BookStack\Uploads\Attachment;
8 use Illuminate\Database\Eloquent\Builder;
9 use Illuminate\Database\Eloquent\Collection;
10 use Illuminate\Database\Eloquent\Factories\HasFactory;
11 use Illuminate\Database\Eloquent\Relations\BelongsTo;
12 use Illuminate\Database\Eloquent\Relations\HasMany;
13 use Illuminate\Database\Eloquent\Relations\HasOne;
14
15 /**
16  * Class Page.
17  * @property EntityPageData $pageData
18  * @property int          $chapter_id
19  * @property string       $html
20  * @property string       $markdown
21  * @property string       $text
22  * @property bool         $template
23  * @property bool         $draft
24  * @property int          $revision_count
25  * @property string       $editor
26  * @property Chapter      $chapter
27  * @property Collection   $attachments
28  * @property Collection   $revisions
29  * @property PageRevision $currentRevision
30  */
31 class Page extends BookChild
32 {
33     use HasFactory;
34
35     public string $textField = 'text';
36     public string $htmlField = 'html';
37     protected $hidden = ['html', 'markdown', 'text', 'pivot', 'deleted_at',  'entity_id', 'entity_type'];
38     protected $fillable = ['name', 'priority'];
39
40     protected $casts = [
41         'draft'    => 'boolean',
42         'template' => 'boolean',
43     ];
44
45     /**
46      * Get the entities that are visible to the current user.
47      */
48     public function scopeVisible(Builder $query): Builder
49     {
50         $query = app()->make(PermissionApplicator::class)->restrictDraftsOnPageQuery($query);
51
52         return parent::scopeVisible($query);
53     }
54
55     /**
56      * Get the chapter that this page is in, If applicable.
57      */
58     public function chapter(): BelongsTo
59     {
60         return $this->belongsTo(Chapter::class);
61     }
62
63     /**
64      * Check if this page has a chapter.
65      */
66     public function hasChapter(): bool
67     {
68         return $this->chapter()->count() > 0;
69     }
70
71     /**
72      * Get the associated page revisions, ordered by created date.
73      * Only provides actual saved page revision instances, Not drafts.
74      */
75     public function revisions(): HasMany
76     {
77         return $this->allRevisions()
78             ->where('type', '=', 'version')
79             ->orderBy('created_at', 'desc')
80             ->orderBy('id', 'desc');
81     }
82
83     /**
84      * Get the current revision for the page if existing.
85      */
86     public function currentRevision(): HasOne
87     {
88         return $this->hasOne(PageRevision::class)
89             ->where('type', '=', 'version')
90             ->orderBy('created_at', 'desc')
91             ->orderBy('id', 'desc');
92     }
93
94     /**
95      * Get all revision instances assigned to this page.
96      * Includes all types of revisions.
97      */
98     public function allRevisions(): HasMany
99     {
100         return $this->hasMany(PageRevision::class);
101     }
102
103     /**
104      * Get the attachments assigned to this page.
105      */
106     public function attachments(): HasMany
107     {
108         return $this->hasMany(Attachment::class, 'uploaded_to')->orderBy('order', 'asc');
109     }
110
111     /**
112      * Get the url of this page.
113      */
114     public function getUrl(string $path = ''): string
115     {
116         $parts = [
117             'books',
118             urlencode($this->book_slug ?? $this->book->slug),
119             $this->draft ? 'draft' : 'page',
120             $this->draft ? $this->id : urlencode($this->slug),
121             trim($path, '/'),
122         ];
123
124         return url('/' . implode('/', $parts));
125     }
126
127     /**
128      * Get the ID-based permalink for this page.
129      */
130     public function getPermalink(): string
131     {
132         return url("/link/{$this->id}");
133     }
134
135     /**
136      * Get this page for JSON display.
137      */
138     public function forJsonDisplay(): self
139     {
140         $refreshed = $this->refresh()->unsetRelations()->load(['tags', 'createdBy', 'updatedBy', 'ownedBy']);
141         $refreshed->setHidden(array_diff($refreshed->getHidden(), ['html', 'markdown']));
142         $refreshed->setAttribute('raw_html', $refreshed->html);
143         $refreshed->setAttribute('html', (new PageContent($refreshed))->render());
144
145         return $refreshed;
146     }
147
148     /**
149      * @return HasOne<EntityPageData, $this>
150      */
151     public function relatedData(): HasOne
152     {
153         return $this->hasOne(EntityPageData::class, 'page_id', 'id');
154     }
155 }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.