<?php
namespace News\Models;
use Carbon\Carbon;
use Johncms\Casts\FormattedDate;
use News\Section;
use News\Utils\Helpers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Johncms\Casts\SpecialChars;
use Johncms\Users\User;
/**
* @mixin Builder
*
* @property $id - Идентификатор
* @property $section_id - Родительский раздел
* @property $active - Активность
* @property $active_from - Дата начала активности
* @property $active_to - Дата завершения активности
* @property $name - Название
* @property $page_title - Заголовок страницы
* @property $code - Символьный код
* @property $preview_text - Краткое описание статьи в списке
* @property $preview_text_safe - Краткое описание статьи в списке в безопасном виде
* @property $text - Текст с описанием
* @property $text_safe - Текст с описанием в безопасном виде
* @property $view_count - Количество просмотров
* @property $keywords - Ключевые слова
* @property $description - Описание
* @property $tags - Tags
* @property $created_at - Дата создания
* @property $updated_at - Дата изменения
* @property $created_by - Автор
* @property $updated_by - Пользователь, изменивший запись
*
* Computed properties
* @property NewsSection $parentSection - Родительский раздел
* @property User $author - Author
* @property NewsVote $votes - Votes for the article
* @property $url - URL адрес страницы просмотра статьи
* @property $rating - Article rating
* @property $current_vote - The user's current vote.
* @property $comments_count
* @property $display_date
* @method NewsArticle search()
* @method NewsArticle active()
* @method NewsArticle lastDays($day_count)
*/
class NewsArticle extends Model
{
use SoftDeletes;
protected $table = 'news_articles';
protected $fillable = [
'active',
'active_from',
'active_to',
'section_id',
'name',
'page_title',
'code',
'keywords',
'description',
'preview_text',
'text',
'tags',
'view_count',
'created_by',
'updated_by',
];
protected $casts = [
'active' => 'bool',
'active_from' => FormattedDate::class,
'active_to' => FormattedDate::class,
'section_id' => 'integer',
'view_count' => 'integer',
'name' => SpecialChars::class,
'page_title' => SpecialChars::class,
'keywords' => SpecialChars::class,
'description' => SpecialChars::class,
'tags' => SpecialChars::class,
'created_at' => FormattedDate::class,
'updated_at' => FormattedDate::class,
];
private $rating_cache;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
/** @var User $user */
$user = di(User::class);
$this->perPage = $user->config->kmess;
}
/**
* Adding a search index to the query
*
* @param Builder $query
* @return Builder
*/
public function scopeSearch(Builder $query): Builder
{
return $query->leftJoin('news_search_index', 'news_articles.id', '=', 'news_search_index.article_id')
->addSelect('news_articles.*');
}
/**
* Only active
*
* @param Builder $query
* @return Builder
*/
public function scopeActive(Builder $query): Builder
{
return $query->where('active', 1)
->where(
function (Builder $builder) {
$builder->whereNull('active_from')->orWhere('active_from', '<=', Carbon::now());
}
)
->where(
function (Builder $builder) {
$builder->whereNull('active_to')->orWhere('active_to', '>=', Carbon::now());
}
);
}
/**
* For last n days
*
* @param Builder $query
* @param int $days
* @return Builder
*/
public function scopeLastDays(Builder $query, int $days = 3): Builder
{
$date = Carbon::now()->addDays(-$days)->format('Y-m-d 00:00:00');
return $query->where('active_from', '>=', $date)->orWhere(
function (Builder $builder) use ($date) {
$builder->whereNull('active_from')->where('created_at', '>=', $date);
}
);
}
public function parentSection(): HasOne
{
return $this->hasOne(NewsSection::class, 'id', 'section_id');
}
public function author(): HasOne
{
return $this->hasOne(User::class, 'id', 'created_by');
}
/**
* Returns the url of the section page
*
* @return string
*/
public function getUrlAttribute(): string
{
$url = '';
if (! empty($this->section_id)) {
$url = (new Section())->getCachedPath($this->section_id) . '/';
}
return '/news/' . $url . $this->code . '.html';
}
/**
* Returns the url of the section page
*
* @return string
*/
public function getTextSafeAttribute(): string
{
return Helpers::purifyHtml($this->text);
}
/**
* Returns the url of the section page
*
* @return string
*/
public function getPreviewTextSafeAttribute(): string
{
return Helpers::purifyHtml($this->preview_text);
}
/**
* Votes
*
* @return HasMany
*/
public function votes(): HasMany
{
return $this->hasMany(NewsVote::class, 'article_id', 'id');
}
/**
* Comments
*
* @return HasMany
*/
public function comments(): HasMany
{
return $this->hasMany(NewsComments::class, 'article_id', 'id');
}
/**
* Article rating
*
* @return int
*/
public function getRatingAttribute(): int
{
if ($this->rating_cache !== null) {
return $this->rating_cache;
}
$this->rating_cache = $this->votes()->sum('vote');
return $this->rating_cache;
}
/**
* The user's current vote.
*
* @return int
*/
public function getCurrentVoteAttribute(): int
{
/** @var User $user */
$user = di(User::class);
if (! $user->isValid()) {
return 0;
}
/** @var NewsVote $vote */
$vote = $this->votes()->where('user_id', $user->id)->first();
if ($vote === null) {
return 0;
}
return $vote->vote;
}
/**
* Tags
*
* @param $value
* @return array
*/
public function getTagsAttribute($value): array
{
$tags = [];
if (! empty($value)) {
$tags = explode(',', $value);
$tags = array_map('trim', $tags);
$tags = array_map('htmlspecialchars', $tags);
}
return $tags;
}
public function getDisplayDateAttribute(): string
{
if (! empty($this->active_from)) {
return $this->active_from;
}
return $this->created_at;
}
}