226 lines
6.1 KiB
PHP
226 lines
6.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Contracts\ImportExport;
|
|
use App\Contracts\Service;
|
|
use App\Models\Aircraft;
|
|
use App\Models\Airport;
|
|
use App\Models\Expense;
|
|
use App\Models\Fare;
|
|
use App\Models\Flight;
|
|
use App\Models\FlightFieldValue;
|
|
use App\Models\Subfleet;
|
|
use App\Services\ImportExport\AircraftImporter;
|
|
use App\Services\ImportExport\AirportImporter;
|
|
use App\Services\ImportExport\ExpenseImporter;
|
|
use App\Services\ImportExport\FareImporter;
|
|
use App\Services\ImportExport\FlightImporter;
|
|
use App\Services\ImportExport\SubfleetImporter;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Validation\ValidationException;
|
|
use League\Csv\Exception;
|
|
use League\Csv\Reader;
|
|
|
|
class ImportService extends Service
|
|
{
|
|
/**
|
|
* Throw a validation error back up because it will automatically show
|
|
* itself under the CSV file upload, and nothing special needs to be done
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
protected function throwError($error, ?\Exception $e = null): void
|
|
{
|
|
Log::error($error);
|
|
if ($e instanceof \Exception) {
|
|
Log::error($e->getMessage());
|
|
}
|
|
|
|
$validator = Validator::make([], []);
|
|
$validator->errors()->add('csv_file', $error);
|
|
|
|
throw new ValidationException($validator);
|
|
}
|
|
|
|
/**
|
|
* @throws ValidationException
|
|
*/
|
|
public function openCsv(string $csv_file): ?Reader
|
|
{
|
|
try {
|
|
$reader = Reader::createFromPath($csv_file, 'r');
|
|
$reader->setDelimiter(',');
|
|
$reader->setHeaderOffset(0);
|
|
$reader->setEnclosure('"');
|
|
$reader->setEscape('\\');
|
|
|
|
return $reader;
|
|
} catch (Exception $exception) {
|
|
$this->throwError('Error opening CSV: '.$exception->getMessage(), $exception);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Run the actual importer, pass in one of the Import classes which implements
|
|
* the ImportExport interface
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
protected function runImport(string $file_path, ImportExport $importer): array
|
|
{
|
|
$reader = $this->openCsv($file_path);
|
|
|
|
array_keys($importer->getColumns());
|
|
$header_rows = $reader->getHeader();
|
|
$records = $reader->getRecords($header_rows);
|
|
foreach ($records as $offset => $row) {
|
|
// turn it into a collection and run some filtering
|
|
$row = collect($row)->map(function ($val, $index): ?string {
|
|
$val = trim($val);
|
|
$val = str_ireplace(['\\n', '\\r'], '', $val);
|
|
|
|
return $val === '' ? null : $val;
|
|
})->toArray();
|
|
|
|
// Try to validate
|
|
$validator = Validator::make($row, $importer->getColumns());
|
|
if ($validator->fails()) {
|
|
$errors = 'Error in row '.$offset.','.implode(';', $validator->errors()->all());
|
|
$importer->errorLog($errors);
|
|
|
|
continue;
|
|
}
|
|
|
|
$importer->import($row, $offset);
|
|
}
|
|
|
|
return $importer->status;
|
|
}
|
|
|
|
/**
|
|
* Import aircraft
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function importAircraft(string $csv_file, bool $delete_previous = true): array
|
|
{
|
|
if ($delete_previous) {
|
|
Aircraft::truncate();
|
|
|
|
// Log::warning('Aircraft table truncated by User: '.Auth::id().' , '.Auth::user()->name_private);
|
|
}
|
|
|
|
$importer = new AircraftImporter();
|
|
|
|
return $this->runImport($csv_file, $importer);
|
|
}
|
|
|
|
/**
|
|
* Import airports
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function importAirports(string $csv_file, bool $delete_previous = true): array
|
|
{
|
|
if ($delete_previous) {
|
|
Airport::truncate();
|
|
}
|
|
|
|
$importer = new AirportImporter();
|
|
|
|
return $this->runImport($csv_file, $importer);
|
|
}
|
|
|
|
/**
|
|
* Import expenses
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function importExpenses(string $csv_file, bool $delete_previous = true): array
|
|
{
|
|
if ($delete_previous) {
|
|
Expense::truncate();
|
|
}
|
|
|
|
$importer = new ExpenseImporter();
|
|
|
|
return $this->runImport($csv_file, $importer);
|
|
}
|
|
|
|
/**
|
|
* Import fares
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function importFares(string $csv_file, bool $delete_previous = true): array
|
|
{
|
|
if ($delete_previous) {
|
|
Fare::truncate();
|
|
}
|
|
|
|
$importer = new FareImporter();
|
|
|
|
return $this->runImport($csv_file, $importer);
|
|
}
|
|
|
|
/**
|
|
* Import flights
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function importFlights(string $csv_file, ?string $delete_previous = null): array
|
|
{
|
|
if (!in_array($delete_previous, [null, '', '0'], true)) {
|
|
// If delete_previous contains all, then delete everything
|
|
if ($delete_previous === 'all') {
|
|
Flight::truncate();
|
|
FlightFieldValue::truncate();
|
|
} elseif ($delete_previous === 'core') {
|
|
// Delete all flights where the owner_type is null
|
|
Flight::whereNull('owner_type')->delete();
|
|
}
|
|
}
|
|
|
|
$importer = new FlightImporter();
|
|
|
|
return $this->runImport($csv_file, $importer);
|
|
}
|
|
|
|
/**
|
|
* Import subfleets
|
|
*
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function importSubfleets(string $csv_file, bool $delete_previous = true): array
|
|
{
|
|
if ($delete_previous) {
|
|
Subfleet::truncate();
|
|
DB::table('subfleet_rank')->truncate();
|
|
DB::table('flight_subfleet')->truncate();
|
|
DB::table('typerating_subfleet')->truncate();
|
|
|
|
// Log::warning('Subfleet and tied relationship tables truncated by User: '.Auth::id().' , '.Auth::user()->name_private);
|
|
}
|
|
|
|
$importer = new SubfleetImporter();
|
|
|
|
return $this->runImport($csv_file, $importer);
|
|
}
|
|
}
|