Initial commit
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Concerns\SortsLists;
|
||||
use App\Services\WellService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/**
|
||||
* Studnie - migracja sites/site401.php (część read-only: lista + wyszukiwanie
|
||||
* + paginacja). Database-first na bazie `softspm`.
|
||||
*
|
||||
* Wydajność: legacy robił N+1 (osobne podzapytania o pompę, silnik i stan
|
||||
* ON/OFF dla KAŻDEGO wiersza). Tu wszystko w JEDNYM zapytaniu z JOIN-ami
|
||||
* (+ podzapytanie po ostatni ON/OFF). Parytet wyników do weryfikacji na
|
||||
* serwerze testowym - patrz README_SOFTSPM.md.
|
||||
*/
|
||||
class WellController extends Controller
|
||||
{
|
||||
use SortsLists;
|
||||
|
||||
/** Status "Wszystkie" - wartość spoza słownika (jak legacy: 100). */
|
||||
private const STATUS_ALL = 100;
|
||||
|
||||
/** Sortowalne kolumny listy: klucz nagłówka => kolumna SQL (z aliasów joinów). */
|
||||
private const SORTABLE = [
|
||||
'name' => 'w.WLL_NAME',
|
||||
'bariera' => 'w.WLL_BARIERA',
|
||||
'pump' => 'p.PUP_NAME',
|
||||
'pump_no' => 'drp.DRS_SN_NUMBER',
|
||||
'engine' => 'e.ENG_NAME',
|
||||
'engine_no' => 'dre.DRS_SN_NUMBER',
|
||||
'type' => 'w.WLL_SYS_TYPE',
|
||||
];
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$department = $request->session()->get('department');
|
||||
$search = trim((string) $request->query('q', ''));
|
||||
// Domyślny status jak w legacy: 3.
|
||||
$status = (int) $request->query('status', 3);
|
||||
|
||||
[$sort, $dir] = $this->sortParams($request);
|
||||
|
||||
// Słownik statusów do filtra (legacy: DIC_ID in (3,4) + "Wszystkie").
|
||||
$statusOptions = DB::connection('softspm')
|
||||
->table('sys_dictionaries')
|
||||
->whereIn('DIC_ID', [3, 4])
|
||||
->orderBy('DIC_ID')
|
||||
->pluck('DIC_POL_LANG', 'DIC_ID');
|
||||
|
||||
$wells = $this->buildQuery($department, $search, $status)
|
||||
->when($sort !== null, fn ($q) => $q->orderBy(self::SORTABLE[$sort], $dir))
|
||||
->orderBy('w.WLL_NAME')
|
||||
->paginate(20)
|
||||
->withQueryString();
|
||||
|
||||
// Stan ON/OFF dociągany tylko dla 20 widocznych studni (wydajność).
|
||||
$this->attachOnOff($wells);
|
||||
|
||||
return view('wells.index', [
|
||||
'wells' => $wells,
|
||||
'search' => $search,
|
||||
'status' => $status,
|
||||
'statusOptions' => $statusOptions,
|
||||
'statusAll' => self::STATUS_ALL,
|
||||
'department' => $department,
|
||||
]);
|
||||
}
|
||||
|
||||
/** Formularz dodania studni (migracja site301A). */
|
||||
public function create(WellService $wells)
|
||||
{
|
||||
return view('wells.create', $this->formLookups($wells));
|
||||
}
|
||||
|
||||
/** Zapis nowej studni (migracja site301inf, dodawanie). */
|
||||
public function store(Request $request, WellService $wells)
|
||||
{
|
||||
$data = $this->validateWell($request, $wells, isUpdate: false);
|
||||
|
||||
$drsId = $wells->create(
|
||||
$data,
|
||||
$request->session()->get('department'),
|
||||
$request->user()->USR_USERNAME,
|
||||
);
|
||||
|
||||
return redirect()
|
||||
->route('wells.index')
|
||||
->with('status', 'Dodano studnię „'.$data['name'].'".');
|
||||
}
|
||||
|
||||
/** Formularz edycji studni (migracja site301E). */
|
||||
public function edit(int $drs, WellService $wells)
|
||||
{
|
||||
$well = $wells->findForEdit($drs);
|
||||
abort_if(! $well, 404);
|
||||
|
||||
return view('wells.edit', $this->formLookups($wells) + ['well' => $well]);
|
||||
}
|
||||
|
||||
/** Aktualizacja studni (migracja site301inf, subWellUpdate). */
|
||||
public function update(int $drs, Request $request, WellService $wells)
|
||||
{
|
||||
$data = $this->validateWell($request, $wells, isUpdate: true);
|
||||
|
||||
$wells->update($drs, $data, $request->user()->USR_USERNAME);
|
||||
|
||||
return redirect()
|
||||
->route('wells.index')
|
||||
->with('status', 'Zaktualizowano studnię „'.$data['name'].'".');
|
||||
}
|
||||
|
||||
/** Wspólne słowniki do formularzy dodania/edycji. */
|
||||
private function formLookups(WellService $wells): array
|
||||
{
|
||||
return [
|
||||
'waterIntakes' => $wells->waterIntakes(),
|
||||
'categories' => $wells->dictionaryById('WELL_CATEGORY'),
|
||||
'statuses' => $wells->dictionaryById('WELL_STATUS_LEVEL_01'),
|
||||
'sysTypes' => $wells->dictionaryDescriptions('WELL_SYSTEM_TYPE'),
|
||||
'statusDescs' => $wells->dictionaryDescriptions('WELL_STATUS_LEVEL_03'),
|
||||
];
|
||||
}
|
||||
|
||||
/** Walidacja + normalizacja pól formularza studni. */
|
||||
private function validateWell(Request $request, WellService $wells, bool $isUpdate): array
|
||||
{
|
||||
$rules = [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'water_intake_id' => ['required', 'integer', 'min:1'],
|
||||
'category_id' => ['required', 'integer'],
|
||||
'status_id' => ['required', 'integer'],
|
||||
'latitude' => ['nullable', 'string', 'max:128'],
|
||||
'longitude' => ['nullable', 'string', 'max:128'],
|
||||
];
|
||||
|
||||
if ($isUpdate) {
|
||||
$rules += [
|
||||
'well_id' => ['required', 'integer'],
|
||||
'pp_scope' => ['nullable', 'string', 'max:16'],
|
||||
'hh_scope' => ['nullable', 'string', 'max:16'],
|
||||
'sys_type' => ['nullable', 'string', 'max:128'],
|
||||
'status_desc' => ['nullable', 'string', 'max:255'],
|
||||
'available_date' => ['nullable', 'date'],
|
||||
'build_time' => ['nullable', 'string', 'max:8'],
|
||||
'wle_id' => ['nullable', 'integer'],
|
||||
];
|
||||
} else {
|
||||
$rules += [
|
||||
'diameter' => ['nullable', 'string', 'max:32'],
|
||||
'depth' => ['nullable', 'string', 'max:32'],
|
||||
'supply' => ['nullable', 'string', 'max:32'],
|
||||
'available_date' => ['nullable', 'date'],
|
||||
];
|
||||
}
|
||||
|
||||
$data = $request->validate($rules);
|
||||
|
||||
// Unikalność nazwy tylko przy dodawaniu (legacy sprawdzał przed INSERT).
|
||||
if (! $isUpdate && $wells->nameExists($data['name'])) {
|
||||
throw ValidationException::withMessages(['name' => 'Studnia o tej nazwie już istnieje.']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jedno zapytanie zastępujące listę + N+1 z legacy.
|
||||
*
|
||||
* Mapowanie tabel legacy:
|
||||
* seg_wells (w) - studnia
|
||||
* seg_dev_resources (drw,12) - zasób studni: DRS_ID, dział, status
|
||||
* seg_well_pump_eng_rel (rel) - powiązanie studnia↔pompa/silnik
|
||||
* seg_dev_resources (drp,10) - zasób pompy (nr seryjny)
|
||||
* seg_pumps (p) - pompa (nazwa)
|
||||
* seg_dev_resources (dre,11) - zasób silnika (nr seryjny)
|
||||
* seg_engines (e) - silnik (nazwa)
|
||||
* seg_dev_resources_det (507) - ostatni stan ON/OFF
|
||||
*/
|
||||
private function buildQuery(?string $department, string $search, int $status)
|
||||
{
|
||||
// UWAGA WYDAJNOŚĆ: NIE łączymy tu ostatniego ON/OFF z seg_dev_resources_det
|
||||
// (tabela ma miliardy wierszy) - agregacja po całości była wąskim gardłem
|
||||
// paginacji. Stan ON/OFF dociągamy osobno tylko dla bieżącej strony
|
||||
// w attachOnOff().
|
||||
return DB::connection('softspm')
|
||||
->table('seg_wells as w')
|
||||
->leftJoin('seg_dev_resources as drw', function ($j) {
|
||||
$j->on('drw.DRS_DEV_ID', '=', 'w.WLL_ID')->where('drw.DRS_DEV_TYPE', '=', 12);
|
||||
})
|
||||
->leftJoin('seg_well_pump_eng_rel as rel', 'rel.RWL_WLL_ID', '=', 'w.WLL_ID')
|
||||
// Pompa
|
||||
->leftJoin('seg_dev_resources as drp', function ($j) {
|
||||
$j->on('drp.DRS_ID', '=', 'rel.RWL_PUP_DRS_ID')->where('drp.DRS_DEV_TYPE', '=', 10);
|
||||
})
|
||||
->leftJoin('seg_pumps as p', 'p.PUP_ID', '=', 'drp.DRS_DEV_ID')
|
||||
// Silnik
|
||||
->leftJoin('seg_dev_resources as dre', function ($j) {
|
||||
$j->on('dre.DRS_ID', '=', 'rel.RWL_ENG_DRS_ID')->where('dre.DRS_DEV_TYPE', '=', 11);
|
||||
})
|
||||
->leftJoin('seg_engines as e', 'e.ENG_ID', '=', 'dre.DRS_DEV_ID')
|
||||
->where('drw.DRS_DEPARTMENT', $department)
|
||||
->when($search !== '', fn ($q) => $q->where('w.WLL_NAME', 'like', '%'.$search.'%'))
|
||||
->when($status !== self::STATUS_ALL, fn ($q) => $q->where('drw.DRS_STATUS_DIC_ID', $status))
|
||||
->select([
|
||||
'drw.DRS_ID as drs_id',
|
||||
'w.WLL_NAME as well_name',
|
||||
'w.WLL_BARIERA as bariera',
|
||||
'p.PUP_NAME as pump_name',
|
||||
'drp.DRS_SN_NUMBER as pump_no',
|
||||
'e.ENG_NAME as engine_name',
|
||||
'dre.DRS_SN_NUMBER as engine_no',
|
||||
'w.WLL_SYS_TYPE as sys_type',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dociąga ostatni stan ON/OFF (DRD_RESOURCES_DETAIL=507) TYLKO dla studni
|
||||
* z bieżącej strony - po ich DRS_ID (indeks INX_DRD_DRS_DETAIL_DATE),
|
||||
* zamiast agregować całą tabelę seg_dev_resources_det. Każdy wiersz
|
||||
* dostaje właściwość ->onoff.
|
||||
*/
|
||||
private function attachOnOff(\Illuminate\Contracts\Pagination\LengthAwarePaginator $wells): void
|
||||
{
|
||||
$ids = collect($wells->items())->pluck('drs_id')->filter()->values()->all();
|
||||
|
||||
$values = empty($ids) ? collect() : DB::connection('softspm')
|
||||
->table('seg_dev_resources_det as d')
|
||||
->joinSub(
|
||||
DB::connection('softspm')
|
||||
->table('seg_dev_resources_det')
|
||||
->select('DRD_DRS_ID', DB::raw('MAX(DRD_ID) as max_id'))
|
||||
->where('DRD_RESOURCES_DETAIL', 507)
|
||||
->whereIn('DRD_DRS_ID', $ids)
|
||||
->groupBy('DRD_DRS_ID'),
|
||||
'mx',
|
||||
'mx.max_id',
|
||||
'=',
|
||||
'd.DRD_ID'
|
||||
)
|
||||
->pluck('d.DRD_VALUE', 'd.DRD_DRS_ID');
|
||||
|
||||
foreach ($wells->items() as $row) {
|
||||
$row->onoff = $values[$row->drs_id] ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user