138 lines
4.3 KiB
PHP
138 lines
4.3 KiB
PHP
<?php
|
||
|
||
namespace App;
|
||
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
|
||
|
||
class Ejaculation extends Model
|
||
{
|
||
use HasEagerLimit;
|
||
|
||
const SOURCE_WEB = 'web';
|
||
const SOURCE_CSV = 'csv';
|
||
const SOURCE_WEBHOOK = 'webhook';
|
||
|
||
protected $fillable = [
|
||
'user_id', 'ejaculated_date',
|
||
'note', 'geo_latitude', 'geo_longitude', 'link', 'source',
|
||
'is_private', 'is_too_sensitive', 'discard_elapsed_time',
|
||
'checkin_webhook_id'
|
||
];
|
||
|
||
protected $dates = [
|
||
'ejaculated_date'
|
||
];
|
||
|
||
public function user()
|
||
{
|
||
return $this->belongsTo('App\User');
|
||
}
|
||
|
||
public function tags()
|
||
{
|
||
return $this->belongsToMany('App\Tag')->withTimestamps();
|
||
}
|
||
|
||
public function textTags()
|
||
{
|
||
return implode(' ', $this->tags->map(function ($v) {
|
||
return $v->name;
|
||
})->all());
|
||
}
|
||
|
||
public function likes()
|
||
{
|
||
return $this->hasMany(Like::class);
|
||
}
|
||
|
||
public function scopeVisibleToTimeline(Builder $query)
|
||
{
|
||
return $query->whereIn('ejaculations.source', [Ejaculation::SOURCE_WEB, Ejaculation::SOURCE_WEBHOOK]);
|
||
}
|
||
|
||
public function scopeWithLikes(Builder $query)
|
||
{
|
||
if (Auth::check()) {
|
||
// TODO - このスコープを使うことでlikesが常に直近10件で絞られるのは汚染されすぎ感がある。別名を付与できないか?
|
||
// - (ejaculation_id, user_id) でユニークなわけですが、is_liked はサブクエリ発行させるのとLeft JoinしてNULLかどうかで結果を見るのどっちがいいんでしょうね
|
||
return $query
|
||
->with([
|
||
'likes' => function ($query) {
|
||
$query->latest()->take(10);
|
||
},
|
||
'likes.user' => function ($query) {
|
||
$query->where('is_protected', false)
|
||
->where('private_likes', false)
|
||
->orWhere('id', Auth::id());
|
||
}
|
||
])
|
||
->withCount([
|
||
'likes',
|
||
'likes as is_liked' => function ($query) {
|
||
$query->where('user_id', Auth::id());
|
||
}
|
||
]);
|
||
} else {
|
||
return $query
|
||
->with([
|
||
'likes' => function ($query) {
|
||
$query->latest()->take(10);
|
||
},
|
||
'likes.user' => function ($query) {
|
||
$query->where('is_protected', false)
|
||
->where('private_likes', false);
|
||
}
|
||
])
|
||
->withCount('likes')
|
||
->addSelect(DB::raw('0 as is_liked'));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* このチェックインと同じ情報を流用してチェックインするためのURLを生成
|
||
* @return string
|
||
*/
|
||
public function makeCheckinURL(): string
|
||
{
|
||
return route('checkin', [
|
||
'link' => $this->link,
|
||
'tags' => $this->textTags(),
|
||
'is_private' => $this->is_private,
|
||
'is_too_sensitive' => $this->is_too_sensitive,
|
||
]);
|
||
}
|
||
|
||
public function ejaculatedSpan(): string
|
||
{
|
||
if (array_key_exists('ejaculated_span', $this->attributes)) {
|
||
if ($this->ejaculated_span === null) {
|
||
return '精通';
|
||
}
|
||
if ($this->discard_elapsed_time) {
|
||
return '0日 0時間 0分'; // TODO: 気の効いたフレーズにする
|
||
}
|
||
|
||
return $this->ejaculated_span;
|
||
} else {
|
||
$previous = Ejaculation::select('ejaculated_date')
|
||
->where('user_id', $this->user_id)
|
||
->where('ejaculated_date', '<', $this->ejaculated_date)
|
||
->orderByDesc('ejaculated_date')
|
||
->first();
|
||
|
||
if ($previous === null) {
|
||
return '精通';
|
||
}
|
||
if ($this->discard_elapsed_time) {
|
||
return '0日 0時間 0分';
|
||
}
|
||
|
||
return $this->ejaculated_date->diff($previous->ejaculated_date)->format('%a日 %h時間 %i分');
|
||
}
|
||
}
|
||
}
|