1 <?php namespace BookStack\Entities;
3 use BookStack\Actions\Activity;
4 use BookStack\Actions\Comment;
5 use BookStack\Actions\Tag;
6 use BookStack\Actions\View;
7 use BookStack\Auth\Permissions\EntityPermission;
8 use BookStack\Auth\Permissions\JointPermission;
11 use Illuminate\Database\Eloquent\Relations\MorphMany;
15 * The base class for book-like items such as pages, chapters & books.
16 * This is not a database model in itself but extended.
18 * @property integer $id
19 * @property string $name
20 * @property string $slug
21 * @property Carbon $created_at
22 * @property Carbon $updated_at
23 * @property int $created_by
24 * @property int $updated_by
25 * @property boolean $restricted
27 * @package BookStack\Entities
29 class Entity extends Ownable
33 * @var string - Name of property where the main text content is found
35 public $textField = 'description';
38 * @var float - Multiplier for search indexing.
40 public $searchFactor = 1.0;
43 * Get the morph class for this model.
44 * Set here since, due to folder changes, the namespace used
45 * in the database no longer matches the class namespace.
48 public function getMorphClass()
50 return 'BookStack\\Entity';
54 * Compares this entity to another given entity.
55 * Matches by comparing class and id.
59 public function matches($entity)
61 return [get_class($this), $this->id] === [get_class($entity), $entity->id];
65 * Checks if an entity matches or contains another given entity.
66 * @param Entity $entity
69 public function matchesOrContains(Entity $entity)
71 $matches = [get_class($this), $this->id] === [get_class($entity), $entity->id];
77 if (($entity->isA('chapter') || $entity->isA('page')) && $this->isA('book')) {
78 return $entity->book_id === $this->id;
81 if ($entity->isA('page') && $this->isA('chapter')) {
82 return $entity->chapter_id === $this->id;
89 * Gets the activity objects for this entity.
90 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
92 public function activity()
94 return $this->morphMany(Activity::class, 'entity')->orderBy('created_at', 'desc');
98 * Get View objects for this entity.
100 public function views()
102 return $this->morphMany(View::class, 'viewable');
105 public function viewCountQuery()
107 return $this->views()->selectRaw('viewable_id, sum(views) as view_count')->groupBy('viewable_id');
111 * Get the Tag models that have been user assigned to this entity.
112 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
114 public function tags()
116 return $this->morphMany(Tag::class, 'entity')->orderBy('order', 'asc');
120 * Get the comments for an entity
121 * @param bool $orderByCreated
124 public function comments($orderByCreated = true)
126 $query = $this->morphMany(Comment::class, 'entity');
127 return $orderByCreated ? $query->orderBy('created_at', 'asc') : $query;
131 * Get the related search terms.
132 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
134 public function searchTerms()
136 return $this->morphMany(SearchTerm::class, 'entity');
140 * Get this entities restrictions.
142 public function permissions()
144 return $this->morphMany(EntityPermission::class, 'restrictable');
148 * Check if this entity has a specific restriction set against it.
153 public function hasRestriction($role_id, $action)
155 return $this->permissions()->where('role_id', '=', $role_id)
156 ->where('action', '=', $action)->count() > 0;
160 * Get the entity jointPermissions this is connected to.
161 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
163 public function jointPermissions()
165 return $this->morphMany(JointPermission::class, 'entity');
169 * Allows checking of the exact class, Used to check entity type.
170 * Cleaner method for is_a.
174 public static function isA($type)
176 return static::getType() === strtolower($type);
183 public static function getType()
185 return strtolower(static::getClassName());
189 * Get an instance of an entity of the given type.
193 public static function getEntityInstance($type)
195 $types = ['Page', 'Book', 'Chapter', 'Bookshelf'];
196 $className = str_replace([' ', '-', '_'], '', ucwords($type));
197 if (!in_array($className, $types)) {
201 return app('BookStack\\Entities\\' . $className);
205 * Gets a limited-length version of the entities name.
209 public function getShortName($length = 25)
211 if (mb_strlen($this->name) <= $length) {
214 return mb_substr($this->name, 0, $length - 3) . '...';
218 * Get the body text of this entity.
221 public function getText()
223 return $this->{$this->textField};
227 * Get an excerpt of this entity's descriptive content to the specified length.
231 public function getExcerpt(int $length = 100)
233 $text = $this->getText();
234 if (mb_strlen($text) > $length) {
235 $text = mb_substr($text, 0, $length-3) . '...';
241 * Return a generalised, common raw query that can be 'unioned' across entities.
244 public function entityRawQuery()
250 * Get the url of this entity
254 public function getUrl($path = '/')