Просмотр файла app/Models/Story.php

Размер файла: 5.57Kb
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Models;
  6.  
  7. use App\Services\Str;
  8. use App\Services\View;
  9. use MotorORM\Builder;
  10. use MotorORM\Collection;
  11.  
  12. /**
  13. * Class Story
  14. *
  15. * @property int $id
  16. * @property int $user_id
  17. * @property string $slug
  18. * @property string $title
  19. * @property string $text
  20. * @property int $rating
  21. * @property int $reads
  22. * @property bool $locked
  23. * @property int $created_at
  24. *
  25. * @property-read User $user
  26. * @property-read Poll $poll
  27. * @property-read Favorite $favorite
  28. * @property-read Collection<Tag> $tags
  29. * @property-read Collection<File> $files
  30. * @property-read Collection<Comment> $comments
  31. * @property-read Collection<Read> $storyReads
  32. * @property-read Collection<Poll> $polls
  33. * @property-read Collection<Favorite> $favorites
  34. */
  35. class Story extends Model
  36. {
  37. protected string $filePath = __DIR__ . '/../../database/stories.csv';
  38.  
  39. /**
  40. * Директория загрузки файлов
  41. */
  42. public string $uploadPath = '/uploads/stories';
  43.  
  44. /**
  45. * The attributes that should be cast.
  46. */
  47. protected array $casts = [
  48. 'rating' => 'int',
  49. 'reads' => 'int',
  50. 'locked' => 'bool',
  51. ];
  52.  
  53. /**
  54. * Возвращает связь пользователя
  55. *
  56. * @return Builder
  57. */
  58. public function user(): Builder
  59. {
  60. return $this->hasOne(User::class, 'id', 'user_id');
  61. }
  62.  
  63. /**
  64. * Возвращает связь голосования пользователя
  65. *
  66. * @return Builder
  67. */
  68. public function poll(): Builder
  69. {
  70. return $this->hasOne(Poll::class, 'entity_id')
  71. ->where('user_id', getUser('id'))
  72. ->where('entity_name', 'story');
  73. }
  74.  
  75. /**
  76. * Возвращает связь голосований
  77. *
  78. * @return Builder
  79. */
  80. public function polls(): Builder
  81. {
  82. return $this->hasMany(Poll::class, 'entity_id')
  83. ->where('entity_name', 'story');
  84. }
  85.  
  86. /**
  87. * Возвращает связь просмотров
  88. *
  89. * @return Builder
  90. */
  91. public function storyReads(): Builder
  92. {
  93. return $this->hasMany(Read::class);
  94. }
  95.  
  96. /**
  97. * Возвращает связь файлов
  98. *
  99. * @return Builder
  100. */
  101. public function files(): Builder
  102. {
  103. return $this->hasMany(File::class);
  104. }
  105.  
  106. /**
  107. * Возвращает связь комментариев
  108. *
  109. * @return Builder
  110. */
  111. public function comments(): Builder
  112. {
  113. return $this->hasMany(Comment::class);
  114. }
  115.  
  116. /**
  117. * Возвращает связь избранного пользователя
  118. *
  119. * @return Builder
  120. */
  121. public function favorite(): Builder
  122. {
  123. return $this->hasOne(Favorite::class, 'story_id')
  124. ->where('user_id', getUser('id'));
  125. }
  126.  
  127. /**
  128. * Возвращает связь с избранным
  129. *
  130. * @return Builder
  131. */
  132. public function favorites(): Builder
  133. {
  134. return $this->hasMany(Favorite::class);
  135. }
  136.  
  137. /**
  138. * Возвращает связь с тегами
  139. *
  140. * @return Builder
  141. */
  142. public function tags(): Builder
  143. {
  144. return $this->hasMany(Tag::class);
  145. }
  146.  
  147. /**
  148. * Delete story
  149. *
  150. * @return int
  151. */
  152. public function delete(): int
  153. {
  154. // delete files
  155. foreach ($this->files as $file) {
  156. $file->delete();
  157. }
  158.  
  159. // delete comments
  160. foreach ($this->comments as $comment) {
  161. $comment->delete();
  162. }
  163.  
  164. // delete reads
  165. foreach ($this->storyReads as $read) {
  166. $read->delete();
  167. }
  168.  
  169. // delete polls
  170. foreach ($this->polls as $poll) {
  171. $poll->delete();
  172. }
  173.  
  174. // delete favorites
  175. foreach ($this->favorites as $favorite) {
  176. $favorite->delete();
  177. }
  178.  
  179. // delete tags
  180. foreach ($this->tags as $tag) {
  181. $tag->delete();
  182. }
  183.  
  184. return parent::delete();
  185. }
  186.  
  187. /**
  188. * Возвращает сокращенный текст статьи
  189. *
  190. * @param int $words
  191. *
  192. * @return string
  193. */
  194. public function shortText(int $words = 100): string
  195. {
  196. $more = app(View::class)->fetch('app/_more', ['link' => $this->getLink()]);
  197.  
  198. if (str_contains($this->text, '[cut]')) {
  199. return bbCode(current(explode('[cut]', $this->text))) . $more;
  200. }
  201.  
  202. if (Str::wordCount($this->text) > $words) {
  203. return bbCodeTruncate($this->text, $words) . $more;
  204. }
  205.  
  206. return bbCode($this->text);
  207. }
  208.  
  209. /**
  210. * Get format rating
  211. *
  212. * @return string Форматированное число
  213. */
  214. public function getRating(): string
  215. {
  216. if ($this->rating > 0) {
  217. $rating = '<span style="color:#00aa00">+' . $this->rating . '</span>';
  218. } elseif ($this->rating < 0) {
  219. $rating = '<span style="color:#ff0000">' . $this->rating . '</span>';
  220. } else {
  221. $rating = '<span>0</span>';
  222. }
  223.  
  224. return $rating;
  225. }
  226.  
  227. /**
  228. * Get tags
  229. *
  230. * @return string
  231. */
  232. public function getTags(): string
  233. {
  234. $tagList = [];
  235. foreach ($this->tags as $tag) {
  236. $tagList[] = '<a href="/tags/' . urlencode(escape($tag->tag)) . '">' . escape($tag->tag) . '</a>';
  237. }
  238.  
  239. return implode(', ', $tagList);
  240. }
  241.  
  242. /**
  243. * Get link
  244. *
  245. * @return string
  246. */
  247. public function getLink(): string
  248. {
  249. return sprintf('/%s-%d', $this->slug, $this->id);
  250. }
  251. }