View file app/Models/Story.php

File size: 5.57Kb
<?php

declare(strict_types=1);

namespace App\Models;

use App\Services\Str;
use App\Services\View;
use MotorORM\Builder;
use MotorORM\Collection;

/**
 * Class Story
 *
 * @property int $id
 * @property int $user_id
 * @property string $slug
 * @property string $title
 * @property string $text
 * @property int $rating
 * @property int $reads
 * @property bool $locked
 * @property int $created_at
 *
 * @property-read User $user
 * @property-read Poll $poll
 * @property-read Favorite $favorite
 * @property-read Collection<Tag> $tags
 * @property-read Collection<File> $files
 * @property-read Collection<Comment> $comments
 * @property-read Collection<Read> $storyReads
 * @property-read Collection<Poll> $polls
 * @property-read Collection<Favorite> $favorites
 */
class Story extends Model
{
    protected string $filePath = __DIR__ . '/../../database/stories.csv';

    /**
     * Директория загрузки файлов
     */
    public string $uploadPath = '/uploads/stories';

    /**
     * The attributes that should be cast.
     */
    protected array $casts = [
        'rating' => 'int',
        'reads'  => 'int',
        'locked' => 'bool',
    ];

    /**
     * Возвращает связь пользователя
     *
     * @return Builder
     */
    public function user(): Builder
    {
        return $this->hasOne(User::class, 'id', 'user_id');
    }

    /**
     * Возвращает связь голосования пользователя
     *
     * @return Builder
     */
    public function poll(): Builder
    {
        return $this->hasOne(Poll::class, 'entity_id')
            ->where('user_id', getUser('id'))
            ->where('entity_name', 'story');
    }

    /**
     * Возвращает связь голосований
     *
     * @return Builder
     */
    public function polls(): Builder
    {
        return $this->hasMany(Poll::class, 'entity_id')
            ->where('entity_name', 'story');
    }

    /**
     * Возвращает связь просмотров
     *
     * @return Builder
     */
    public function storyReads(): Builder
    {
        return $this->hasMany(Read::class);
    }

    /**
     * Возвращает связь файлов
     *
     * @return Builder
     */
    public function files(): Builder
    {
        return $this->hasMany(File::class);
    }

    /**
     * Возвращает связь комментариев
     *
     * @return Builder
     */
    public function comments(): Builder
    {
        return $this->hasMany(Comment::class);
    }

    /**
     * Возвращает связь избранного пользователя
     *
     * @return Builder
     */
    public function favorite(): Builder
    {
        return $this->hasOne(Favorite::class, 'story_id')
            ->where('user_id', getUser('id'));
    }

    /**
     * Возвращает связь с избранным
     *
     * @return Builder
     */
    public function favorites(): Builder
    {
        return $this->hasMany(Favorite::class);
    }

    /**
     * Возвращает связь с тегами
     *
     * @return Builder
     */
    public function tags(): Builder
    {
        return $this->hasMany(Tag::class);
    }

    /**
     * Delete story
     *
     * @return int
     */
    public function delete(): int
    {
        // delete files
        foreach ($this->files as $file) {
            $file->delete();
        }

        // delete comments
        foreach ($this->comments as $comment) {
            $comment->delete();
        }

        // delete reads
        foreach ($this->storyReads as $read) {
            $read->delete();
        }

        // delete polls
        foreach ($this->polls as $poll) {
            $poll->delete();
        }

        // delete favorites
        foreach ($this->favorites as $favorite) {
            $favorite->delete();
        }

        // delete tags
        foreach ($this->tags as $tag) {
            $tag->delete();
        }

        return parent::delete();
    }

    /**
     * Возвращает сокращенный текст статьи
     *
     * @param int $words
     *
     * @return string
     */
    public function shortText(int $words = 100): string
    {
        $more = app(View::class)->fetch('app/_more', ['link' => $this->getLink()]);

        if (str_contains($this->text, '[cut]')) {
            return bbCode(current(explode('[cut]', $this->text))) . $more;
        }

        if (Str::wordCount($this->text) > $words) {
            return bbCodeTruncate($this->text, $words) . $more;
        }

        return bbCode($this->text);
    }

    /**
     * Get format rating
     *
     * @return string Форматированное число
     */
    public function getRating(): string
    {
        if ($this->rating > 0) {
            $rating = '<span style="color:#00aa00">+' . $this->rating . '</span>';
        } elseif ($this->rating < 0) {
            $rating = '<span style="color:#ff0000">' . $this->rating . '</span>';
        } else {
            $rating = '<span>0</span>';
        }

        return $rating;
    }

    /**
     * Get tags
     *
     * @return string
     */
    public function getTags(): string
    {
        $tagList = [];
        foreach ($this->tags as $tag) {
            $tagList[] = '<a href="/tags/' . urlencode(escape($tag->tag)) . '">' . escape($tag->tag) . '</a>';
        }

        return implode(', ', $tagList);
    }

    /**
     * Get link
     *
     * @return string
     */
    public function getLink(): string
    {
         return sprintf('/%s-%d', $this->slug, $this->id);
    }
}