Add artisan commands to import entries from a CSV file
This commit is contained in:
parent
3315efc83b
commit
2dfb745861
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Event;
|
||||
use App\Models\Room;
|
||||
use App\Models\ScoringGuide;
|
||||
use App\Services\CsvImportService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use function auditionSetting;
|
||||
use function Laravel\Prompts\select;
|
||||
|
||||
class importCheckAuditionsCommand extends Command
|
||||
{
|
||||
protected $signature = 'import:check-auditions';
|
||||
|
||||
protected $description = 'Check the import file for auditions that do not exist in the database';
|
||||
|
||||
protected $csvImporter;
|
||||
|
||||
public function __construct(CsvImportService $csvImporter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->csvImporter = $csvImporter;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$lowestPossibleGrade = 1;
|
||||
$highestPossibleGrade = 12;
|
||||
$events = Event::all();
|
||||
$rows = $this->csvImporter->readCsv(storage_path('app/import/import.csv'));
|
||||
$checkedAuditions = collect();
|
||||
foreach ($rows as $row) {
|
||||
if ($checkedAuditions->contains($row['Instrument'])) {
|
||||
continue;
|
||||
}
|
||||
$checkedAuditions->push($row['Instrument']);
|
||||
|
||||
if (Audition::where('name', $row['Instrument'])->count() > 0) {
|
||||
$this->info('Audition '.$row['Instrument'].' already exists');
|
||||
} else {
|
||||
$this->newLine();
|
||||
$this->alert('Audition '.$row['Instrument'].' does not exist');
|
||||
if ($events->count() === 1) {
|
||||
$newEventId = $events->first()->id;
|
||||
} else {
|
||||
$newEventId = select(
|
||||
label: 'Which event does this audition belong to?',
|
||||
options: $events->pluck('name', 'id')->toArray(),
|
||||
);
|
||||
}
|
||||
$newEventName = $row['Instrument'];
|
||||
$newEventScoreOrder = Audition::max('score_order') + 1;
|
||||
$newEventEntryDeadline = Carbon::yesterday('America/Chicago')->format('Y-m-d');
|
||||
$newEventEntryFee = Audition::max('entry_fee');
|
||||
$newEventMinimumGrade = select(
|
||||
label: 'What is the minimum grade for this audition?',
|
||||
options: range($lowestPossibleGrade, $highestPossibleGrade)
|
||||
);
|
||||
$newEventMaximumGrade = select(
|
||||
label: 'What is the maximum grade for this audition?',
|
||||
options: range($newEventMinimumGrade, $highestPossibleGrade)
|
||||
);
|
||||
$newEventRoomId = select(
|
||||
label: 'Which room does this audition belong to?',
|
||||
options: Room::pluck('name', 'id')->toArray(),
|
||||
);
|
||||
$newEventScoringGuideId = select(
|
||||
label: 'Which scoring guide should this audition use',
|
||||
options: ScoringGuide::pluck('name', 'id')->toArray(),
|
||||
);
|
||||
if (auditionSetting('advanceTo')) {
|
||||
$newEventForSeating = select(
|
||||
label: 'Is this audition for seating?',
|
||||
options: [
|
||||
1 => 'Yes',
|
||||
0 => 'No',
|
||||
]
|
||||
);
|
||||
$newEventForAdvance = select(
|
||||
label: 'Is this audition for '.auditionSetting('advanceTo').'?',
|
||||
options: [
|
||||
1 => 'Yes',
|
||||
0 => 'No',
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$newEventForSeating = 1;
|
||||
$newEventForAdvance = 0;
|
||||
}
|
||||
|
||||
$this->info('New event ID: '.$newEventId);
|
||||
$this->info('New event name: '.$newEventName);
|
||||
$this->info('New event score order: '.$newEventScoreOrder);
|
||||
$this->info('New event entry deadline: '.$newEventEntryDeadline);
|
||||
$this->info('New event entry fee: '.$newEventEntryFee);
|
||||
$this->info('New event minimum grade: '.$newEventMinimumGrade);
|
||||
$this->info('New event maximum grade: '.$newEventMaximumGrade);
|
||||
$this->info('New event room ID: '.$newEventRoomId);
|
||||
$this->info('New event scoring guide ID: '.$newEventScoringGuideId);
|
||||
$this->info('New event for seating: '.$newEventForSeating);
|
||||
$this->info('New event for advance: '.$newEventForAdvance);
|
||||
|
||||
Audition::create([
|
||||
'event_id' => $newEventId,
|
||||
'name' => $newEventName,
|
||||
'score_order' => $newEventScoreOrder,
|
||||
'entry_deadline' => $newEventEntryDeadline,
|
||||
'entry_fee' => $newEventEntryFee,
|
||||
'minimum_grade' => $newEventMinimumGrade,
|
||||
'maximum_grade' => $newEventMaximumGrade,
|
||||
'room_id' => $newEventRoomId,
|
||||
'scoring_guide_id' => $newEventScoringGuideId,
|
||||
'for_seating' => $newEventForSeating,
|
||||
'for_advancement' => $newEventForAdvance,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use const PHP_EOL;
|
||||
|
||||
use App\Models\School;
|
||||
use App\Services\CsvImportService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class importCheckSchoolsCommand extends Command
|
||||
{
|
||||
protected $signature = 'import:check-schools';
|
||||
|
||||
protected $description = 'Check the import file for schools that do not exist in the database';
|
||||
|
||||
protected $csvImporter;
|
||||
|
||||
public function __construct(CsvImportService $csvImporter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->csvImporter = $csvImporter;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$rows = $this->csvImporter->readCsv(storage_path('app/import/import.csv'));
|
||||
$checkedSchools = collect();
|
||||
foreach ($rows as $row) {
|
||||
if ($checkedSchools->contains($row['School'])) {
|
||||
continue;
|
||||
}
|
||||
$checkedSchools->push($row['School']);
|
||||
if (School::where('name', $row['School'])->count() > 0) {
|
||||
$this->info('School '.$row['School'].' already exists');
|
||||
} else {
|
||||
$this->newLine();
|
||||
$this->alert('School '.$row['School'].' does not exist'.PHP_EOL.'Creating school...');
|
||||
School::create(['name' => $row['School']]);
|
||||
$this->info('School '.$row['School'].' created');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Entry;
|
||||
use App\Models\School;
|
||||
use App\Models\Student;
|
||||
use App\Services\CsvImportService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class importCheckStudentsCommand extends Command
|
||||
{
|
||||
protected $signature = 'import:check-students';
|
||||
|
||||
protected $description = 'Check the import file for students that do not exist in the database';
|
||||
|
||||
protected $csvImporter;
|
||||
|
||||
public function __construct(CsvImportService $csvImporter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->csvImporter = $csvImporter;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$purge = $this->confirm('Do you want to purge the database of existing students and entries?', false);
|
||||
if ($purge) {
|
||||
Entry::all()->map(function ($entry) {
|
||||
$entry->delete();
|
||||
});
|
||||
Student::all()->map(function ($student) {
|
||||
$student->delete();
|
||||
});
|
||||
$this->info('Database purged');
|
||||
}
|
||||
$schools = School::pluck('id', 'name');
|
||||
$rows = $this->csvImporter->readCsv(storage_path('app/import/import.csv'));
|
||||
$checkedStudents = collect();
|
||||
foreach ($rows as $row) {
|
||||
$uniqueData = $row['School'].$row['LastName'].$row['LastName'];
|
||||
if ($checkedStudents->contains($uniqueData)) {
|
||||
// continue;
|
||||
}
|
||||
$checkedStudents->push($uniqueData);
|
||||
|
||||
$currentFirstName = $row['FirstName'];
|
||||
$currentLastName = $row['LastName'];
|
||||
$currentSchoolName = $row['School'];
|
||||
$currentSchoolId = $schools[$currentSchoolName];
|
||||
|
||||
if (Student::where('first_name', $currentFirstName)->where('last_name',
|
||||
$currentLastName)->where('school_id', $currentSchoolId)->count() > 0) {
|
||||
$this->info('Student '.$currentFirstName.' '.$currentLastName.' from '.$currentSchoolName.' already exists');
|
||||
} else {
|
||||
$this->alert('Student '.$currentFirstName.' '.$currentLastName.' from '.$currentSchoolName.' does not exist');
|
||||
$newStudent = Student::create([
|
||||
'school_id' => $currentSchoolId,
|
||||
'first_name' => $currentFirstName,
|
||||
'last_name' => $currentLastName,
|
||||
'grade' => $row['Grade'],
|
||||
]);
|
||||
$this->info('Student '.$currentFirstName.' '.$currentLastName.' from '.$currentSchoolName.' created with id of: '.$newStudent->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\School;
|
||||
use App\Models\Student;
|
||||
use App\Services\CsvImportService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class importImportEntriesCommand extends Command
|
||||
{
|
||||
protected $signature = 'import';
|
||||
|
||||
protected $description = 'Import entries from the import.csv file. First check schools, then students, then auditions, then run this import command';
|
||||
|
||||
protected $csvImporter;
|
||||
|
||||
public function __construct(CsvImportService $csvImporter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->csvImporter = $csvImporter;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$checkAuditions = $this->confirm('Do you want to check the auditions in the import for validity first?', true);
|
||||
if ($checkAuditions) {
|
||||
$this->call('import:check-auditions');
|
||||
}
|
||||
|
||||
$checkSchools = $this->confirm('Do you want to check the schools in the import for validity first?', true);
|
||||
if ($checkSchools) {
|
||||
$this->call('import:check-schools');
|
||||
}
|
||||
|
||||
$checkStudents = $this->confirm('Do you want to check the students in the import for validity first?', true);
|
||||
if ($checkStudents) {
|
||||
$this->call('import:check-students');
|
||||
}
|
||||
|
||||
$purge = $this->confirm('Do you want to purge the database of existing entries?', false);
|
||||
if ($purge) {
|
||||
Entry::all()->map(function ($entry) {
|
||||
$entry->delete();
|
||||
});
|
||||
$this->info('Database purged');
|
||||
}
|
||||
$schools = School::pluck('id', 'name');
|
||||
$auditions = Audition::pluck('id', 'name');
|
||||
$rows = $this->csvImporter->readCsv(storage_path('app/import/import.csv'));
|
||||
foreach ($rows as $row) {
|
||||
$schoolId = $schools[$row['School']];
|
||||
$student = Student::where('first_name', $row['FirstName'])->where('last_name',
|
||||
$row['LastName'])->where('school_id', $schoolId)->first();
|
||||
if (! $student) {
|
||||
$this->error('Student '.$row['FirstName'].' '.$row['LastName'].' from '.$row['School'].' does not exist');
|
||||
|
||||
return;
|
||||
}
|
||||
$auditionId = $auditions[$row['Instrument']];
|
||||
try {
|
||||
Entry::create([
|
||||
'student_id' => $student->id,
|
||||
'audition_id' => $auditionId,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->warn('Entry already exists for student '.$student->full_name().' in audition '.$row['Instrument']);
|
||||
}
|
||||
$this->info('Entry created for student '.$student->full_name().' in audition '.$row['Instrument']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class CsvImportService
|
||||
{
|
||||
/**
|
||||
* Read a CSV file and return its contents as an array
|
||||
*
|
||||
* @param string $filePath Full path to the CSV file
|
||||
* @param bool $trimHeaders Whether to trim whitespace from header names
|
||||
* @return array Array of rows with header keys
|
||||
*/
|
||||
public function readCsv(string $filePath, bool $trimHeaders = true): array
|
||||
{
|
||||
if (! file_exists($filePath)) {
|
||||
throw new \RuntimeException("File not found: {$filePath}");
|
||||
}
|
||||
|
||||
$handle = fopen($filePath, 'r');
|
||||
if ($handle === false) {
|
||||
throw new \RuntimeException("Unable to open file: {$filePath}");
|
||||
}
|
||||
|
||||
$header = null;
|
||||
$rows = [];
|
||||
|
||||
while (($line = fgetcsv($handle, 0, ',')) !== false) {
|
||||
if (! $header) {
|
||||
$header = $trimHeaders ? array_map('trim', $line) : $line;
|
||||
|
||||
continue;
|
||||
}
|
||||
$row = array_combine($header, $line);
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue