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