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;
9 use BookStack\Facades\Permissions;
10 use BookStack\Ownable;
12 use Illuminate\Database\Eloquent\Relations\MorphMany;
16 * The base class for book-like items such as pages, chapters & books.
17 * This is not a database model in itself but extended.
20 * @property string $name
21 * @property string $slug
22 * @property Carbon $created_at
23 * @property Carbon $updated_at
24 * @property int $created_by
25 * @property int $updated_by
26 * @property boolean $restricted
28 * @package BookStack\Entities
30 class Entity extends Ownable
34 * @var string - Name of property where the main text content is found
36 public $textField = 'description';
39 * @var float - Multiplier for search indexing.
41 public $searchFactor = 1.0;
44 * Get the morph class for this model.
45 * Set here since, due to folder changes, the namespace used
46 * in the database no longer matches the class namespace.
49 public function getMorphClass()
51 return 'BookStack\\Entity';
55 * Compares this entity to another given entity.
56 * Matches by comparing class and id.
60 public function matches($entity)
62 return [get_class($this), $this->id] === [get_class($entity), $entity->id];
66 * Checks if an entity matches or contains another given entity.
67 * @param Entity $entity
70 public function matchesOrContains(Entity $entity)
72 $matches = [get_class($this), $this->id] === [get_class($entity), $entity->id];
78 if (($entity->isA('chapter') || $entity->isA('page')) && $this->isA('book')) {
79 return $entity->book_id === $this->id;
82 if ($entity->isA('page') && $this->isA('chapter')) {
83 return $entity->chapter_id === $this->id;
90 * Gets the activity objects for this entity.
91 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
93 public function activity()
95 return $this->morphMany(Activity::class, 'entity')
96 ->orderBy('created_at', 'desc');
100 * Get View objects for this entity.
102 public function views()
104 return $this->morphMany(View::class, 'viewable');
108 * Get the Tag models that have been user assigned to this entity.
109 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
111 public function tags()
113 return $this->morphMany(Tag::class, 'entity')->orderBy('order', 'asc');
117 * Get the comments for an entity
118 * @param bool $orderByCreated
121 public function comments($orderByCreated = true)
123 $query = $this->morphMany(Comment::class, 'entity');
124 return $orderByCreated ? $query->orderBy('created_at', 'asc') : $query;
128 * Get the related search terms.
129 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
131 public function searchTerms()
133 return $this->morphMany(SearchTerm::class, 'entity');
137 * Get this entities restrictions.
139 public function permissions()
141 return $this->morphMany(EntityPermission::class, 'restrictable');
145 * Check if this entity has a specific restriction set against it.
150 public function hasRestriction($role_id, $action)
152 return $this->permissions()->where('role_id', '=', $role_id)
153 ->where('action', '=', $action)->count() > 0;
157 * Get the entity jointPermissions this is connected to.
158 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
160 public function jointPermissions()
162 return $this->morphMany(JointPermission::class, 'entity');
166 * Allows checking of the exact class, Used to check entity type.
167 * Cleaner method for is_a.
171 public static function isA($type)
173 return static::getType() === strtolower($type);
180 public static function getType()
182 return strtolower(static::getClassName());
186 * Get the type of this entity.
188 public function type(): string
190 return static::getType();
194 * Get an instance of an entity of the given type.
198 public static function getEntityInstance($type)
200 $types = ['Page', 'Book', 'Chapter', 'Bookshelf'];
201 $className = str_replace([' ', '-', '_'], '', ucwords($type));
202 if (!in_array($className, $types)) {
206 return app('BookStack\\Entities\\' . $className);
210 * Gets a limited-length version of the entities name.
214 public function getShortName($length = 25)
216 if (mb_strlen($this->name) <= $length) {
219 return mb_substr($this->name, 0, $length - 3) . '...';
223 * Get the body text of this entity.
226 public function getText()
228 return $this->{$this->textField};
232 * Get an excerpt of this entity's descriptive content to the specified length.
236 public function getExcerpt(int $length = 100)
238 $text = $this->getText();
239 if (mb_strlen($text) > $length) {
240 $text = mb_substr($text, 0, $length-3) . '...';
246 * Return a generalised, common raw query that can be 'unioned' across entities.
249 public function entityRawQuery()
255 * Get the url of this entity
259 public function getUrl($path = '/')
265 * Rebuild the permissions for this entity.
267 public function rebuildPermissions()
269 /** @noinspection PhpUnhandledExceptionInspection */
270 Permissions::buildJointPermissionsForEntity($this);
274 * Generate and set a new URL slug for this model.
276 public function refreshSlug(): string
278 $generator = new SlugGenerator($this);
279 $this->slug = $generator->generate();