]> BookStack Code Mirror - bookstack/blob - app/Entities/Models/Page.php
WYSIWYG: Updated TinyMCE from 6.5.1 to 6.7.2
[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  *
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 static $listAttributes = ['name', 'id', 'slug', 'book_id', 'chapter_id', 'draft', 'template', 'text', 'created_at', 'updated_at', 'priority'];
36     public static $contentAttributes = ['name', 'id', 'slug', 'book_id', 'chapter_id', 'draft', 'template', 'html', 'text', 'created_at', 'updated_at', 'priority'];
37
38     protected $fillable = ['name', 'priority'];
39
40     public $textField = 'text';
41
42     protected $hidden = ['html', 'markdown', 'text', 'pivot', 'deleted_at'];
43
44     protected $casts = [
45         'draft'    => 'boolean',
46         'template' => 'boolean',
47     ];
48
49     /**
50      * Get the entities that are visible to the current user.
51      */
52     public function scopeVisible(Builder $query): Builder
53     {
54         $query = app()->make(PermissionApplicator::class)->restrictDraftsOnPageQuery($query);
55
56         return parent::scopeVisible($query);
57     }
58
59     /**
60      * Get the chapter that this page is in, If applicable.
61      *
62      * @return BelongsTo
63      */
64     public function chapter()
65     {
66         return $this->belongsTo(Chapter::class);
67     }
68
69     /**
70      * Check if this page has a chapter.
71      */
72     public function hasChapter(): bool
73     {
74         return $this->chapter()->count() > 0;
75     }
76
77     /**
78      * Get the associated page revisions, ordered by created date.
79      * Only provides actual saved page revision instances, Not drafts.
80      */
81     public function revisions(): HasMany
82     {
83         return $this->allRevisions()
84             ->where('type', '=', 'version')
85             ->orderBy('created_at', 'desc')
86             ->orderBy('id', 'desc');
87     }
88
89     /**
90      * Get the current revision for the page if existing.
91      */
92     public function currentRevision(): HasOne
93     {
94         return $this->hasOne(PageRevision::class)
95             ->where('type', '=', 'version')
96             ->orderBy('created_at', 'desc')
97             ->orderBy('id', 'desc');
98     }
99
100     /**
101      * Get all revision instances assigned to this page.
102      * Includes all types of revisions.
103      */
104     public function allRevisions(): HasMany
105     {
106         return $this->hasMany(PageRevision::class);
107     }
108
109     /**
110      * Get the attachments assigned to this page.
111      *
112      * @return HasMany
113      */
114     public function attachments()
115     {
116         return $this->hasMany(Attachment::class, 'uploaded_to')->orderBy('order', 'asc');
117     }
118
119     /**
120      * Get the url of this page.
121      */
122     public function getUrl(string $path = ''): string
123     {
124         $parts = [
125             'books',
126             urlencode($this->book_slug ?? $this->book->slug),
127             $this->draft ? 'draft' : 'page',
128             $this->draft ? $this->id : urlencode($this->slug),
129             trim($path, '/'),
130         ];
131
132         return url('/' . implode('/', $parts));
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->html = (new PageContent($refreshed))->render();
144
145         return $refreshed;
146     }
147
148     /**
149      * Get a visible page by its book and page slugs.
150      * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
151      */
152     public static function getBySlugs(string $bookSlug, string $pageSlug): self
153     {
154         return static::visible()->whereSlugs($bookSlug, $pageSlug)->firstOrFail();
155     }
156 }