260 lines
9.0 KiB
PHP
260 lines
9.0 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Http\Traits\AuthenticatesUser;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Log;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class ParkDetailController extends Controller
|
||
{
|
||
use AuthenticatesUser;
|
||
|
||
/**
|
||
* 駐輪場詳細情報を取得(Ajax用)
|
||
*
|
||
* @param string $management_code
|
||
* @param int $park_id
|
||
* @return \Illuminate\Http\JsonResponse
|
||
*/
|
||
public function show($management_code, $park_id)
|
||
{
|
||
if ($redirect = $this->handleSessionExpired('駐輪場詳細', false)) {
|
||
return $redirect;
|
||
}
|
||
|
||
$userId = session('user_id');
|
||
$management = session('management');
|
||
if (!$management) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 運営元情報取得失敗 user_id=" . $userId);
|
||
return response()->json(['error' => 'Management not found'], 404);
|
||
}
|
||
|
||
// マルチテナント対応:運営元に紐づく駐輪場のみ取得
|
||
$park = $this->getParkInfo($park_id, $management->management_id);
|
||
if (!$park) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場情報取得失敗 park_id=" . $park_id . ", management_id=" . $management->management_id . ", user_id=" . $userId);
|
||
return response()->json(['error' => 'Park not found'], 404);
|
||
}
|
||
|
||
// ゾーン情報取得
|
||
$zones = $this->getZones($park_id);
|
||
|
||
// 予約情報取得
|
||
$reserves = $this->getReserves($park_id);
|
||
|
||
// 車種別の基準台数集計
|
||
$zoneStandardSum = $this->calculateZoneStandardSum($zones);
|
||
|
||
// 車種別の空き台数計算
|
||
$vacancyData = $this->calculateVacancy($zones, $reserves);
|
||
|
||
// 駐輪場ごとの更新可能期間取得
|
||
$parkGracePeriod = $this->getParkGracePeriod($park_id);
|
||
|
||
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 駐輪場詳細取得成功 park_id=" . $park_id . ", management_id=" . $management->management_id . ", user_id=" . $userId);
|
||
|
||
try {
|
||
$html = view('regular_contract.park_detail', compact(
|
||
'park',
|
||
'zones',
|
||
'reserves',
|
||
'zoneStandardSum',
|
||
'vacancyData',
|
||
'parkGracePeriod'
|
||
))->render();
|
||
|
||
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " ビュー生成成功 park_id=" . $park_id . ", HTML長=" . strlen($html));
|
||
|
||
|
||
return response()->json(['html' => $html]);
|
||
} catch (\Exception $e) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " ビュー生成失敗 park_id=" . $park_id . ", error=" . $e->getMessage());
|
||
return response()->json(['error' => 'View rendering failed'], 500);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 駐輪場情報取得(マルチテナントフィルタ適用)
|
||
*
|
||
* 運営元に紐づく駐輪場のみを取得することで、他の運営元のデータが
|
||
* 誤って表示されることを防ぐ。
|
||
*
|
||
* @param int $parkId
|
||
* @param int $managementId
|
||
* @return object|null
|
||
*/
|
||
private function getParkInfo(int $parkId, int $managementId)
|
||
{
|
||
try {
|
||
return DB::table('park')
|
||
->where('park_id', $parkId)
|
||
->where('management_id', $managementId)
|
||
->first();
|
||
} catch (\Exception $e) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場情報取得エラー park_id=" . $parkId . ", error=" . $e->getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* ゾーン情報取得
|
||
*
|
||
* @param int $parkId
|
||
* @return \Illuminate\Support\Collection
|
||
*/
|
||
private function getZones(int $parkId)
|
||
{
|
||
try {
|
||
return DB::table('zone')
|
||
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
|
||
->leftJoin('ptype', 'zone.ptype_id', '=', 'ptype.ptype_id')
|
||
->select(
|
||
'zone.*',
|
||
'psection.psection_subject',
|
||
'ptype.ptype_subject'
|
||
)
|
||
->where('zone.park_id', $parkId)
|
||
->get();
|
||
} catch (\Exception $e) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " zone情報取得失敗 park_id=" . $parkId . ", error=" . $e->getMessage());
|
||
return collect();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 予約情報取得
|
||
*
|
||
* @param int $parkId
|
||
* @return \Illuminate\Support\Collection
|
||
*/
|
||
private function getReserves(int $parkId)
|
||
{
|
||
try {
|
||
return DB::table('reserve')
|
||
->join('zone', function ($join) {
|
||
$join->on('reserve.psection_id', '=', 'zone.psection_id')
|
||
->on('reserve.ptype_id', '=', 'zone.ptype_id');
|
||
})
|
||
->join('ptype', 'zone.ptype_id', '=', 'ptype.ptype_id')
|
||
->where('reserve.park_id', $parkId)
|
||
->where('reserve.valid_flag', 1)
|
||
->select('reserve.*', 'ptype.ptype_subject')
|
||
->get();
|
||
} catch (\Exception $e) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " reserve情報取得失敗 park_id=" . $parkId . ", error=" . $e->getMessage());
|
||
return collect();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 車種別の基準台数集計
|
||
*
|
||
* 駐輪場の車種別定員(zone_standard の合計)を算出する。
|
||
*
|
||
* @param \Illuminate\Support\Collection $zones
|
||
* @return array
|
||
*/
|
||
private function calculateZoneStandardSum($zones)
|
||
{
|
||
$zoneStandardSum = [];
|
||
|
||
foreach ($zones as $zone) {
|
||
$key = $zone->psection_subject; // 「自転車」「原付」など
|
||
if (!isset($zoneStandardSum[$key])) {
|
||
$zoneStandardSum[$key] = 0;
|
||
}
|
||
$zoneStandardSum[$key] += $zone->zone_standard;
|
||
}
|
||
|
||
return $zoneStandardSum;
|
||
}
|
||
|
||
/**
|
||
* 車種別の空き台数計算
|
||
*
|
||
* 予約を考慮した実際の空き台数を算出する。
|
||
* 許容台数から現在台数を引き、さらに有効な予約件数分を減算することで、正確な空き状況を把握する。
|
||
*
|
||
* @param \Illuminate\Support\Collection $zones
|
||
* @param \Illuminate\Support\Collection $reserves
|
||
* @return array
|
||
*/
|
||
private function calculateVacancy($zones, $reserves)
|
||
{
|
||
$vacancyData = [];
|
||
|
||
// zone_tolerance - zone_number を集計
|
||
foreach ($zones as $zone) {
|
||
$key = $zone->psection_id . '_' . $zone->ptype_subject;
|
||
if (!isset($vacancyData[$key])) {
|
||
$vacancyData[$key] = 0;
|
||
}
|
||
$vacancyData[$key] += ($zone->zone_tolerance - $zone->zone_number);
|
||
}
|
||
|
||
// reserve件数分を減算
|
||
foreach ($reserves as $reserve) {
|
||
$key = $reserve->psection_id . '_' . $reserve->ptype_subject;
|
||
if (isset($vacancyData[$key])) {
|
||
$vacancyData[$key] -= 1;
|
||
}
|
||
}
|
||
|
||
return $vacancyData;
|
||
}
|
||
|
||
/**
|
||
* 駐輪場の更新可能期間取得
|
||
*
|
||
* @param int $parkId
|
||
* @return object|null
|
||
*/
|
||
private function getParkGracePeriod(int $parkId)
|
||
{
|
||
try {
|
||
return DB::table('park')
|
||
->select(
|
||
'park_id',
|
||
'update_grace_period_start_date',
|
||
'update_grace_period_start_time',
|
||
'update_grace_period_end_date',
|
||
'update_grace_period_end_time'
|
||
)
|
||
->where('park_id', $parkId)
|
||
->first();
|
||
} catch (\Exception $e) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場更新可能期間取得失敗 park_id=" . $parkId . ", error=" . $e->getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public function showWait($reserve_id)
|
||
{
|
||
$reserve = DB::table('reserve')->where('reserve_id', $reserve_id)->first();
|
||
$park = DB::table('park')->where('park_id', $reserve->park_id)->first();
|
||
|
||
$zones = DB::table('zone')
|
||
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
|
||
->leftJoin('ptype', 'zone.ptype_id', '=', 'ptype.ptype_id')
|
||
->select('zone.*', 'psection.psection_subject', 'ptype.ptype_subject')
|
||
->where('zone.park_id', $park->park_id)
|
||
->get();
|
||
|
||
$zoneStandardSum = [];
|
||
foreach ($zones as $zone) {
|
||
$key = $zone->psection_subject; // 「自転車」「原付」など
|
||
if (!isset($zoneStandardSum[$key])) {
|
||
$zoneStandardSum[$key] = 0;
|
||
}
|
||
$zoneStandardSum[$key] += $zone->zone_standard;
|
||
}
|
||
|
||
// 必要なら他テーブルJOINや追加情報も取得
|
||
return response()->json([
|
||
'html' => view('park_waitlist.park_detail', compact('park', 'zones', 'reserve', 'zoneStandardSum'))->render()
|
||
]);
|
||
}
|
||
}
|