511 lines
16 KiB
PHP
511 lines
16 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Park;
|
|
use App\Models\Price;
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Database\Query\Builder;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use RuntimeException;
|
|
|
|
final class ReserveService
|
|
{
|
|
/**
|
|
* 一覧取得(検索+ページング)
|
|
* Why: Controller を薄くするため、クエリ構築をここに集約する。
|
|
*
|
|
* @return array{list: LengthAwarePaginator, sort: string, sort_type: string, user_id: string, park_id: ?int, reserve_date_from: mixed, reserve_date_to: mixed, keyword: string, valid_flag: ?string, parkOptions: array}
|
|
*/
|
|
public function paginate(array $payload): array
|
|
{
|
|
$sort = $this->normalizeSort((string) $payload['sort'], $this->sortableKeys());
|
|
$sortType = $this->normalizeSortType((string) $payload['sortType']);
|
|
|
|
$q = $this->baseQuery();
|
|
|
|
$this->applyFilters($q, $payload);
|
|
$this->applySort($q, $sort, $sortType);
|
|
|
|
$parkOptions = Park::query()
|
|
->orderBy('park_id', 'asc')
|
|
->pluck('park_name', 'park_id')
|
|
->toArray();
|
|
|
|
$list = $q->paginate(50);
|
|
|
|
$this->attachPriceNames($list);
|
|
|
|
return [
|
|
'list' => $list,
|
|
'sort' => $sort,
|
|
'sort_type' => $sortType,
|
|
|
|
'user_id' => (string) $payload['userId'],
|
|
'park_id' => $payload['parkId'],
|
|
'reserve_date_from' => $payload['fromDt'],
|
|
'reserve_date_to' => $payload['toDt'],
|
|
'keyword' => (string) $payload['keyword'],
|
|
'valid_flag' => $payload['validFlag'],
|
|
|
|
'parkOptions' => $parkOptions,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 新規画面用のプルダウンなど。
|
|
*/
|
|
public function getFormOptions(): array
|
|
{
|
|
$userTypes = DB::table('usertype')
|
|
->orderBy('user_categoryid', 'asc')
|
|
->get([
|
|
'user_categoryid',
|
|
'usertype_subject1',
|
|
'usertype_subject2',
|
|
'usertype_subject3',
|
|
])
|
|
->map(function (object $row): object {
|
|
$labels = array_filter([
|
|
$row->usertype_subject1,
|
|
$row->usertype_subject2,
|
|
$row->usertype_subject3,
|
|
], static fn ($v): bool => $v !== null && $v !== '');
|
|
|
|
$row->display_name = $labels ? implode('/', $labels) : '';
|
|
return $row;
|
|
});
|
|
|
|
$parks = Park::query()
|
|
->orderBy('park_id', 'asc')
|
|
->get(['park_id', 'park_name']);
|
|
|
|
$priceOptions = $this->getUnifiedPriceOptions();
|
|
|
|
return [
|
|
'userTypes' => $userTypes,
|
|
'parks' => $parks,
|
|
'priceOptions' => $priceOptions,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 新規画面用:プルダウン等
|
|
*/
|
|
public function getCreateForm(): array
|
|
{
|
|
$userOptions = DB::table('user')
|
|
->orderBy('user_id', 'asc')
|
|
->limit(5000)
|
|
->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
|
|
->toArray();
|
|
|
|
$parkOptions = DB::table('park')
|
|
->orderBy('park_id', 'asc')
|
|
->pluck('park_name', 'park_id')
|
|
->toArray();
|
|
|
|
$userTypeOptions = DB::table('usertype')
|
|
->orderBy('user_categoryid')
|
|
->select([
|
|
'user_categoryid',
|
|
DB::raw("
|
|
COALESCE(
|
|
NULLIF(TRIM(CONCAT_WS('/',
|
|
NULLIF(TRIM(usertype_subject1), ''),
|
|
NULLIF(TRIM(usertype_subject2), ''),
|
|
NULLIF(TRIM(usertype_subject3), '')
|
|
)), ''),
|
|
print_name
|
|
) AS label
|
|
")
|
|
])
|
|
->pluck('label', 'user_categoryid')
|
|
->toArray();
|
|
|
|
$priceOptions = Schema::hasTable('price')
|
|
? DB::table('price')
|
|
->orderBy('price_parkplaceid')
|
|
->pluck('prine_name', 'price_parkplaceid')
|
|
->toArray()
|
|
: [];
|
|
|
|
$psectionOptions = Schema::hasTable('psection')
|
|
? DB::table('psection')
|
|
->orderBy('psection_id')
|
|
->pluck(
|
|
Schema::hasColumn('psection', 'psection_subject') ? 'psection_subject' : 'psection_id',
|
|
'psection_id'
|
|
)
|
|
->toArray()
|
|
: [];
|
|
|
|
$ptypeOptions = Schema::hasTable('ptype')
|
|
? DB::table('ptype')
|
|
->orderBy('ptype_id')
|
|
->pluck(
|
|
Schema::hasColumn('ptype', 'ptype_subject') ? 'ptype_subject' : 'ptype_id',
|
|
'ptype_id'
|
|
)
|
|
->toArray()
|
|
: [];
|
|
|
|
return [
|
|
'userOptions' => $userOptions,
|
|
'parkOptions' => $parkOptions,
|
|
'userTypeOptions' => $userTypeOptions,
|
|
'priceOptions' => $priceOptions,
|
|
'psectionOptions' => $psectionOptions,
|
|
'ptypeOptions' => $ptypeOptions,
|
|
];
|
|
}
|
|
|
|
|
|
/**
|
|
* 編集画面用:対象レコード+プルダウン
|
|
*/
|
|
public function getEditForm(int $reserveId): array
|
|
{
|
|
$row = DB::table('reserve')->where('reserve_id', $reserveId)->first();
|
|
if ($row === null) {
|
|
abort(404);
|
|
}
|
|
|
|
$userOptions = DB::table('user')
|
|
->orderBy('user_id', 'asc')
|
|
->limit(5000)
|
|
->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
|
|
->toArray();
|
|
|
|
$parkOptions = DB::table('park')
|
|
->orderBy('park_id', 'asc')
|
|
->pluck('park_name', 'park_id')
|
|
->toArray();
|
|
|
|
$userTypeOptions = DB::table('usertype')
|
|
->orderBy('user_categoryid')
|
|
->select([
|
|
'user_categoryid',
|
|
DB::raw("
|
|
COALESCE(
|
|
NULLIF(TRIM(CONCAT_WS('/',
|
|
NULLIF(TRIM(usertype_subject1), ''),
|
|
NULLIF(TRIM(usertype_subject2), ''),
|
|
NULLIF(TRIM(usertype_subject3), '')
|
|
)), ''),
|
|
print_name
|
|
) AS label
|
|
")
|
|
])
|
|
->pluck('label', 'user_categoryid')
|
|
->toArray();
|
|
|
|
$priceOptions = Schema::hasTable('price')
|
|
? DB::table('price')
|
|
->orderBy('price_parkplaceid')
|
|
->pluck('prine_name', 'price_parkplaceid')
|
|
->toArray()
|
|
: [];
|
|
|
|
$psectionOptions = Schema::hasTable('psection')
|
|
? DB::table('psection')
|
|
->orderBy('psection_id')
|
|
->pluck(
|
|
Schema::hasColumn('psection', 'psection_subject') ? 'psection_subject' : 'psection_id',
|
|
'psection_id'
|
|
)
|
|
->toArray()
|
|
: [];
|
|
$ptypeOptions = Schema::hasTable('ptype')
|
|
? DB::table('ptype')
|
|
->orderBy('ptype_id')
|
|
->pluck(
|
|
Schema::hasColumn('ptype', 'ptype_subject') ? 'ptype_subject' : 'ptype_id',
|
|
'ptype_id'
|
|
)
|
|
->toArray()
|
|
: [];
|
|
|
|
return [
|
|
'row' => $row,
|
|
'userOptions' => $userOptions,
|
|
'parkOptions' => $parkOptions,
|
|
'userTypeOptions' => $userTypeOptions,
|
|
'priceOptions' => $priceOptions,
|
|
'psectionOptions' => $psectionOptions,
|
|
'ptypeOptions' => $ptypeOptions,
|
|
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 更新
|
|
*/
|
|
public function update(int $reserveId, array $payload): void
|
|
{
|
|
$exists = DB::table('reserve')->where('reserve_id', $reserveId)->exists();
|
|
if (!$exists) {
|
|
abort(404);
|
|
}
|
|
|
|
$data = [
|
|
'user_categoryid' => $payload['userCategoryId'],
|
|
'contract_id' => $payload['contractId'],
|
|
'contract_created_at' => $payload['contractCreatedAt'],
|
|
|
|
'user_id' => $payload['userId'],
|
|
'park_id' => $payload['parkId'],
|
|
'price_parkplaceid' => $payload['priceParkplaceId'],
|
|
'psection_id' => $payload['psectionId'],
|
|
'ptype_id' => $payload['ptypeId'],
|
|
'reserve_date' => $payload['reserveDate'],
|
|
'reserve_start' => $payload['reserveStart'],
|
|
'reserve_end' => $payload['reserveEnd'],
|
|
'valid_flag' => $payload['validFlag'],
|
|
'reserve_reduction' => $payload['reserveReduction'],
|
|
'reserve_auto_remind' => $payload['reserveAutoRemind'],
|
|
'reserve_manual_remind' => $payload['reserveManualRemind'],
|
|
'800m_flag' => $payload['flag800m'],
|
|
'reserve_cancelday' => $payload['reserveCancelday'],
|
|
'reserve_manual' => $payload['reserveManual'],
|
|
'reserve_notice' => $payload['reserveNotice'],
|
|
'reserve_type' => $payload['reserveType'],
|
|
'sent_date' => $payload['sentDate'],
|
|
'reserve_order' => $payload['reserveOrder'],
|
|
|
|
'ope_id' => $payload['opeId'],
|
|
'updated_at' => now(),
|
|
];
|
|
|
|
DB::table('reserve')
|
|
->where('reserve_id', $reserveId)
|
|
->update($data);
|
|
}
|
|
|
|
/**
|
|
* 複数削除
|
|
*
|
|
* @return int 削除件数
|
|
*/
|
|
public function deleteMany(array $ids): int
|
|
{
|
|
if ($ids === []) {
|
|
return 0;
|
|
}
|
|
|
|
return (int) DB::table('reserve')
|
|
->whereIn('reserve_id', $ids)
|
|
->delete();
|
|
}
|
|
|
|
private function baseQuery(): Builder
|
|
{
|
|
return DB::table('reserve as r')
|
|
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
|
|
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
|
|
->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id')
|
|
->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id')
|
|
->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid')
|
|
->select([
|
|
'r.reserve_id',
|
|
'r.contract_id',
|
|
'r.contract_created_at',
|
|
'r.user_categoryid',
|
|
'r.user_id',
|
|
'r.park_id',
|
|
'r.price_parkplaceid',
|
|
'r.psection_id',
|
|
'r.ptype_id',
|
|
'r.reserve_date',
|
|
|
|
'r.reserve_reduction',
|
|
'r.reserve_auto_remind',
|
|
'r.reserve_manual_remind',
|
|
DB::raw('r.`800m_flag` as flag_800m'),
|
|
'r.reserve_cancelday',
|
|
'r.valid_flag',
|
|
'r.ope_id',
|
|
'r.reserve_manual',
|
|
'r.reserve_notice',
|
|
'r.sent_date',
|
|
'r.reserve_order',
|
|
'r.reserve_type',
|
|
|
|
DB::raw('u.user_name as user_name'),
|
|
DB::raw('p.park_name as park_name'),
|
|
DB::raw('ps.psection_subject as psection_subject'),
|
|
DB::raw('pt.ptype_subject as ptype_subject'),
|
|
|
|
DB::raw('t.usertype_subject1 as usertype_subject1'),
|
|
DB::raw('t.usertype_subject2 as usertype_subject2'),
|
|
DB::raw('t.usertype_subject3 as usertype_subject3'),
|
|
]);
|
|
}
|
|
|
|
|
|
|
|
private function applyFilters(Builder $q, array $payload): void
|
|
{
|
|
if ($payload['userId'] !== '') {
|
|
$q->where('r.user_id', 'like', '%' . $payload['userId'] . '%');
|
|
}
|
|
|
|
if ($payload['parkId'] !== null) {
|
|
$q->where('r.park_id', '=', $payload['parkId']);
|
|
}
|
|
|
|
if (!empty($payload['fromDt'])) {
|
|
$q->whereDate('r.reserve_date', '>=', $payload['fromDt']);
|
|
}
|
|
|
|
if (!empty($payload['toDt'])) {
|
|
$q->whereDate('r.reserve_date', '<=', $payload['toDt']);
|
|
}
|
|
|
|
if ($payload['keyword'] !== '') {
|
|
$keyword = $payload['keyword'];
|
|
|
|
$q->where(function (Builder $w) use ($keyword): void {
|
|
$w->where('u.user_name', 'like', '%' . $keyword . '%')
|
|
->orWhere('u.user_phonetic', 'like', '%' . $keyword . '%');
|
|
});
|
|
}
|
|
|
|
if (in_array($payload['validFlag'], ['0', '1'], true)) {
|
|
$q->where('r.valid_flag', '=', (int) $payload['validFlag']);
|
|
}
|
|
}
|
|
|
|
private function applySort(Builder $q, string $sort, string $sortType): void
|
|
{
|
|
$sortMap = [
|
|
'reserve_id' => DB::raw('r.reserve_id'),
|
|
'contract_id' => DB::raw('r.contract_id'),
|
|
'contract_created_at' => DB::raw('r.contract_created_at'), //
|
|
'user_categoryid' => DB::raw('r.user_categoryid'),
|
|
'user_id' => DB::raw('r.user_id'),
|
|
'reserve_date' => DB::raw('r.reserve_date'),
|
|
|
|
'park_name' => DB::raw('p.park_name'),
|
|
'price_parkplaceid' => DB::raw('r.price_parkplaceid'),
|
|
|
|
'psection_subject' => DB::raw('ps.psection_subject'),
|
|
'ptype_subject' => DB::raw('pt.ptype_subject'),
|
|
|
|
'reserve_reduction' => DB::raw('r.reserve_reduction'),
|
|
'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'),
|
|
'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'),
|
|
|
|
'flag_800m' => DB::raw('r.`800m_flag`'), //
|
|
'reserve_cancelday' => DB::raw('r.reserve_cancelday'),
|
|
'valid_flag' => DB::raw('r.valid_flag'),
|
|
|
|
'sent_date' => DB::raw('r.sent_date'),
|
|
'reserve_manual' => DB::raw('r.reserve_manual'),
|
|
'reserve_notice' => DB::raw('r.reserve_notice'),
|
|
'reserve_order' => DB::raw('r.reserve_order'),
|
|
|
|
'reserve_type' => DB::raw('r.reserve_type'), //
|
|
];
|
|
|
|
if (!isset($sortMap[$sort])) {
|
|
return;
|
|
}
|
|
|
|
$q->orderBy($sortMap[$sort], $sortType);
|
|
}
|
|
|
|
|
|
private function sortableKeys(): array
|
|
{
|
|
return [
|
|
'reserve_id',
|
|
'contract_id',
|
|
'contract_created_at',
|
|
'user_categoryid',
|
|
'user_id',
|
|
'reserve_date',
|
|
|
|
'park_name',
|
|
'price_parkplaceid',
|
|
|
|
'psection_subject',
|
|
'ptype_subject',
|
|
|
|
'reserve_reduction',
|
|
'reserve_auto_remind',
|
|
'reserve_manual_remind',
|
|
|
|
'flag_800m',
|
|
'reserve_cancelday',
|
|
'valid_flag',
|
|
|
|
'sent_date',
|
|
'reserve_manual',
|
|
'reserve_notice',
|
|
'reserve_order',
|
|
|
|
'reserve_type',
|
|
];
|
|
}
|
|
|
|
|
|
private function normalizeSort(string $sort, array $sortable): string
|
|
{
|
|
return in_array($sort, $sortable, true) ? $sort : 'reserve_id';
|
|
}
|
|
|
|
private function normalizeSortType(string $sortType): string
|
|
{
|
|
$sortType = strtolower($sortType);
|
|
return $sortType === 'desc' ? 'desc' : 'asc';
|
|
}
|
|
|
|
private function attachPriceNames(LengthAwarePaginator $list): void
|
|
{
|
|
$placeIds = $list->getCollection()
|
|
->pluck('price_parkplaceid')
|
|
->filter()
|
|
->unique()
|
|
->values()
|
|
->all();
|
|
|
|
if ($placeIds === []) {
|
|
return;
|
|
}
|
|
|
|
$priceNames = Price::query()
|
|
->whereIn('price_parkplaceid', $placeIds)
|
|
->pluck('prine_name', 'price_parkplaceid')
|
|
->toArray();
|
|
|
|
$list->setCollection(
|
|
$list->getCollection()->map(function (object $row) use ($priceNames): object {
|
|
$id = $row->price_parkplaceid ?? null;
|
|
|
|
$row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames))
|
|
? $priceNames[$id]
|
|
: null;
|
|
|
|
return $row;
|
|
})
|
|
);
|
|
}
|
|
|
|
|
|
private function getUnifiedPriceOptions()
|
|
{
|
|
return Price::query()
|
|
->select('price_parkplaceid', 'prine_name')
|
|
->get()
|
|
->sortBy('price_parkplaceid', SORT_NATURAL)
|
|
->unique('price_parkplaceid')
|
|
->values();
|
|
}
|
|
|
|
}
|