319 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			319 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Http\Controllers;
 | 
						|
 | 
						|
use App\Ejaculation;
 | 
						|
use App\User;
 | 
						|
use Carbon\Carbon;
 | 
						|
use Carbon\CarbonInterface;
 | 
						|
use Illuminate\Http\Request;
 | 
						|
use Illuminate\Support\Facades\Auth;
 | 
						|
use Illuminate\Support\Facades\DB;
 | 
						|
use Validator;
 | 
						|
 | 
						|
class UserController extends Controller
 | 
						|
{
 | 
						|
    public function redirectMypage()
 | 
						|
    {
 | 
						|
        return redirect()->route('user.profile', ['name' => auth()->user()->name]);
 | 
						|
    }
 | 
						|
 | 
						|
    public function profile($name)
 | 
						|
    {
 | 
						|
        $user = User::where('name', $name)->first();
 | 
						|
        if (empty($user)) {
 | 
						|
            abort(404);
 | 
						|
        }
 | 
						|
 | 
						|
        // チェックインの取得
 | 
						|
        $query = Ejaculation::select(DB::raw(
 | 
						|
            <<<'SQL'
 | 
						|
ejaculations.id,
 | 
						|
ejaculated_date,
 | 
						|
note,
 | 
						|
is_private,
 | 
						|
is_too_sensitive,
 | 
						|
link,
 | 
						|
source,
 | 
						|
to_char(before_dates.before_date, 'YYYY/MM/DD HH24:MI') AS before_date,
 | 
						|
to_char(ejaculated_date - before_dates.before_date, 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
 | 
						|
SQL
 | 
						|
        ))
 | 
						|
            ->joinSub($this->queryBeforeEjaculatedDates(), 'before_dates', 'before_dates.id', '=', 'ejaculations.id')
 | 
						|
            ->where('user_id', $user->id);
 | 
						|
        if (!Auth::check() || $user->id !== Auth::id()) {
 | 
						|
            $query = $query->where('is_private', false);
 | 
						|
        }
 | 
						|
        $ejaculations = $query->orderBy('ejaculated_date', 'desc')
 | 
						|
            ->with('tags')
 | 
						|
            ->withLikes()
 | 
						|
            ->paginate(20);
 | 
						|
 | 
						|
        // よく使っているタグ
 | 
						|
        $tagsQuery = DB::table('ejaculations')
 | 
						|
            ->join('ejaculation_tag', 'ejaculations.id', '=', 'ejaculation_tag.ejaculation_id')
 | 
						|
            ->join('tags', 'ejaculation_tag.tag_id', '=', 'tags.id')
 | 
						|
            ->selectRaw('tags.name, count(*) as count')
 | 
						|
            ->where('ejaculations.user_id', $user->id);
 | 
						|
        if (!Auth::check() || $user->id !== Auth::id()) {
 | 
						|
            $tagsQuery = $tagsQuery->where('ejaculations.is_private', false);
 | 
						|
        }
 | 
						|
        $tags = $tagsQuery->groupBy('tags.name')
 | 
						|
            ->orderBy('count', 'desc')
 | 
						|
            ->limit(10)
 | 
						|
            ->get();
 | 
						|
 | 
						|
        // シコ草
 | 
						|
        $countByDayQuery = $this->countEjaculationByDay($user)
 | 
						|
            ->where('ejaculated_date', '>=', now()->startOfMonth()->subMonths(9))
 | 
						|
            ->where('ejaculated_date', '<', now()->addMonth()->startOfMonth())
 | 
						|
            ->get();
 | 
						|
        $countByDay = [];
 | 
						|
        foreach ($countByDayQuery as $data) {
 | 
						|
            $date = Carbon::createFromFormat('Y/m/d', $data->date);
 | 
						|
            $countByDay[$date->timestamp] = $data->count;
 | 
						|
        }
 | 
						|
 | 
						|
        return view('user.profile')->with(compact('user', 'ejaculations', 'tags', 'countByDay'));
 | 
						|
    }
 | 
						|
 | 
						|
    public function stats($name)
 | 
						|
    {
 | 
						|
        $user = User::where('name', $name)->first();
 | 
						|
        if (empty($user)) {
 | 
						|
            abort(404);
 | 
						|
        }
 | 
						|
 | 
						|
        $availableMonths = $this->makeStatsAvailableMonths($user);
 | 
						|
        $graphData = $this->makeGraphData($user);
 | 
						|
 | 
						|
        return view('user.stats.index')->with(compact('user', 'graphData', 'availableMonths'));
 | 
						|
    }
 | 
						|
 | 
						|
    public function statsYearly($name, $year)
 | 
						|
    {
 | 
						|
        $user = User::where('name', $name)->first();
 | 
						|
        if (empty($user)) {
 | 
						|
            abort(404);
 | 
						|
        }
 | 
						|
 | 
						|
        $validator = Validator::make(compact('year'), [
 | 
						|
            'year' => 'required|date_format:Y'
 | 
						|
        ]);
 | 
						|
        if ($validator->fails()) {
 | 
						|
            return redirect()->route('user.stats', compact('name'));
 | 
						|
        }
 | 
						|
 | 
						|
        $availableMonths = $this->makeStatsAvailableMonths($user);
 | 
						|
        if (!isset($availableMonths[$year])) {
 | 
						|
            return redirect()->route('user.stats', compact('name'));
 | 
						|
        }
 | 
						|
 | 
						|
        $graphData = $this->makeGraphData(
 | 
						|
            $user,
 | 
						|
            Carbon::createFromDate($year, 1, 1, config('app.timezone'))->startOfDay(),
 | 
						|
            Carbon::createFromDate($year, 1, 1, config('app.timezone'))->addYear()->startOfDay()
 | 
						|
        );
 | 
						|
 | 
						|
        return view('user.stats.yearly')
 | 
						|
            ->with(compact('user', 'graphData', 'availableMonths'))
 | 
						|
            ->with('currentYear', (int) $year);
 | 
						|
    }
 | 
						|
 | 
						|
    public function statsMonthly($name, $year, $month)
 | 
						|
    {
 | 
						|
        $user = User::where('name', $name)->first();
 | 
						|
        if (empty($user)) {
 | 
						|
            abort(404);
 | 
						|
        }
 | 
						|
 | 
						|
        $validator = Validator::make(compact('year', 'month'), [
 | 
						|
            'year' => 'required|date_format:Y',
 | 
						|
            'month' => 'required|date_format:m'
 | 
						|
        ]);
 | 
						|
        if ($validator->fails()) {
 | 
						|
            return redirect()->route('user.stats.yearly', compact('name', 'year'));
 | 
						|
        }
 | 
						|
 | 
						|
        $availableMonths = $this->makeStatsAvailableMonths($user);
 | 
						|
        if (!isset($availableMonths[$year]) || !in_array($month, $availableMonths[$year], false)) {
 | 
						|
            return redirect()->route('user.stats.yearly', compact('name', 'year'));
 | 
						|
        }
 | 
						|
 | 
						|
        $graphData = $this->makeGraphData(
 | 
						|
            $user,
 | 
						|
            Carbon::createFromDate($year, $month, 1, config('app.timezone'))->startOfDay(),
 | 
						|
            Carbon::createFromDate($year, $month, 1, config('app.timezone'))->addMonth()->startOfDay()
 | 
						|
        );
 | 
						|
 | 
						|
        return view('user.stats.monthly')
 | 
						|
            ->with(compact('user', 'graphData', 'availableMonths'))
 | 
						|
            ->with('currentYear', (int) $year)
 | 
						|
            ->with('currentMonth', (int) $month);
 | 
						|
    }
 | 
						|
 | 
						|
    public function okazu($name)
 | 
						|
    {
 | 
						|
        $user = User::where('name', $name)->first();
 | 
						|
        if (empty($user)) {
 | 
						|
            abort(404);
 | 
						|
        }
 | 
						|
 | 
						|
        // チェックインの取得
 | 
						|
        $query = Ejaculation::select(DB::raw(
 | 
						|
            <<<'SQL'
 | 
						|
ejaculations.id,
 | 
						|
ejaculated_date,
 | 
						|
note,
 | 
						|
is_private,
 | 
						|
is_too_sensitive,
 | 
						|
link,
 | 
						|
source,
 | 
						|
to_char(before_dates.before_date, 'YYYY/MM/DD HH24:MI') AS before_date,
 | 
						|
to_char(ejaculated_date - before_dates.before_date, 'FMDDD日 FMHH24時間 FMMI分') AS ejaculated_span
 | 
						|
SQL
 | 
						|
        ))
 | 
						|
            ->joinSub($this->queryBeforeEjaculatedDates(), 'before_dates', 'before_dates.id', '=', 'ejaculations.id')
 | 
						|
            ->where('user_id', $user->id)
 | 
						|
            ->where('link', '<>', '');
 | 
						|
        if (!Auth::check() || $user->id !== Auth::id()) {
 | 
						|
            $query = $query->where('is_private', false);
 | 
						|
        }
 | 
						|
        $ejaculations = $query->orderBy('ejaculated_date', 'desc')
 | 
						|
            ->with('tags')
 | 
						|
            ->withLikes()
 | 
						|
            ->paginate(20);
 | 
						|
 | 
						|
        return view('user.profile')->with(compact('user', 'ejaculations'));
 | 
						|
    }
 | 
						|
 | 
						|
    public function likes($name)
 | 
						|
    {
 | 
						|
        $user = User::where('name', $name)->first();
 | 
						|
        if (empty($user)) {
 | 
						|
            abort(404);
 | 
						|
        }
 | 
						|
 | 
						|
        $likes = $user->likes()
 | 
						|
            ->orderBy('created_at', 'desc')
 | 
						|
            ->with('ejaculation.user', 'ejaculation.tags')
 | 
						|
            ->whereHas('ejaculation', function ($query) {
 | 
						|
                $query->where('user_id', Auth::id())
 | 
						|
                    ->orWhere('is_private', false);
 | 
						|
            })
 | 
						|
            ->paginate(20);
 | 
						|
 | 
						|
        return view('user.likes')->with(compact('user', 'likes'));
 | 
						|
    }
 | 
						|
 | 
						|
    private function makeStatsAvailableMonths(User $user): array
 | 
						|
    {
 | 
						|
        $availableMonths = [];
 | 
						|
        $oldest = $user->ejaculations()->orderBy('ejaculated_date')->first();
 | 
						|
        if (isset($oldest)) {
 | 
						|
            $oldestMonth = $oldest->ejaculated_date->startOfMonth();
 | 
						|
            $currentMonth = now()->startOfMonth();
 | 
						|
            for ($month = $currentMonth; $oldestMonth <= $currentMonth; $month = $month->subMonth()) {
 | 
						|
                if (!isset($availableMonths[$month->year])) {
 | 
						|
                    $availableMonths[$month->year] = [];
 | 
						|
                }
 | 
						|
                $availableMonths[$month->year][] = $month->month;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $availableMonths;
 | 
						|
    }
 | 
						|
 | 
						|
    private function makeGraphData(User $user, CarbonInterface $dateSince = null, CarbonInterface $dateUntil = null): array
 | 
						|
    {
 | 
						|
        if ($dateUntil === null) {
 | 
						|
            $dateUntil = now()->addMonth()->startOfMonth();
 | 
						|
        }
 | 
						|
        $dateCondition = [
 | 
						|
            ['ejaculated_date', '<', $dateUntil],
 | 
						|
        ];
 | 
						|
        if ($dateSince !== null) {
 | 
						|
            $dateCondition[] = ['ejaculated_date', '>=', $dateSince];
 | 
						|
        }
 | 
						|
 | 
						|
        $groupByDay = $this->countEjaculationByDay($user)
 | 
						|
            ->where($dateCondition)
 | 
						|
            ->get();
 | 
						|
 | 
						|
        $groupByHour = Ejaculation::select(DB::raw(
 | 
						|
            <<<'SQL'
 | 
						|
to_char(ejaculated_date, 'HH24') AS "hour",
 | 
						|
count(*) AS "count"
 | 
						|
SQL
 | 
						|
        ))
 | 
						|
            ->where('user_id', $user->id)
 | 
						|
            ->where($dateCondition)
 | 
						|
            ->groupBy(DB::raw("to_char(ejaculated_date, 'HH24')"))
 | 
						|
            ->orderBy(DB::raw('1'))
 | 
						|
            ->get();
 | 
						|
 | 
						|
        $dailySum = [];
 | 
						|
        $monthlySum = [];
 | 
						|
        $yearlySum = [];
 | 
						|
        $dowSum = array_fill(0, 7, 0);
 | 
						|
        $hourlySum = array_fill(0, 24, 0);
 | 
						|
 | 
						|
        // 年間グラフ用の配列初期化
 | 
						|
        if ($groupByDay->first() !== null) {
 | 
						|
            $year = Carbon::createFromFormat('Y/m/d', $groupByDay->first()->date)->year;
 | 
						|
            $currentYear = date('Y');
 | 
						|
            for (; $year <= $currentYear; $year++) {
 | 
						|
                $yearlySum[$year] = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        foreach ($groupByDay as $data) {
 | 
						|
            $date = Carbon::createFromFormat('Y/m/d', $data->date);
 | 
						|
            $yearAndMonth = $date->format('Y/m');
 | 
						|
 | 
						|
            $dailySum[$date->timestamp] = $data->count;
 | 
						|
            $yearlySum[$date->year] += $data->count;
 | 
						|
            $dowSum[$date->dayOfWeek] += $data->count;
 | 
						|
            $monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count;
 | 
						|
        }
 | 
						|
 | 
						|
        foreach ($groupByHour as $data) {
 | 
						|
            $hour = (int)$data->hour;
 | 
						|
            $hourlySum[$hour] += $data->count;
 | 
						|
        }
 | 
						|
 | 
						|
        return [
 | 
						|
            'dailySum' => $dailySum,
 | 
						|
            'dowSum' => $dowSum,
 | 
						|
            'monthlySum' => $monthlySum,
 | 
						|
            'yearlyKey' => array_keys($yearlySum),
 | 
						|
            'yearlySum' => array_values($yearlySum),
 | 
						|
            'hourlyKey' => array_keys($hourlySum),
 | 
						|
            'hourlySum' => array_values($hourlySum),
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    private function countEjaculationByDay(User $user)
 | 
						|
    {
 | 
						|
        return Ejaculation::select(DB::raw(
 | 
						|
            <<<'SQL'
 | 
						|
to_char(ejaculated_date, 'YYYY/MM/DD') AS "date",
 | 
						|
count(*) AS "count"
 | 
						|
SQL
 | 
						|
        ))
 | 
						|
            ->where('user_id', $user->id)
 | 
						|
            ->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"))
 | 
						|
            ->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')"));
 | 
						|
    }
 | 
						|
 | 
						|
    private function queryBeforeEjaculatedDates()
 | 
						|
    {
 | 
						|
        return DB::table('ejaculations')->selectRaw(
 | 
						|
            <<<'SQL'
 | 
						|
id,
 | 
						|
(select ejaculated_date from ejaculations e2 where e2.ejaculated_date < ejaculations.ejaculated_date and e2.user_id = ejaculations.user_id order by e2.ejaculated_date desc limit 1) AS before_date
 | 
						|
SQL
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 |