Scobda nomination ensembles #106
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\NominationEnsembles;
|
||||
|
||||
use App\Models\NominationEnsembleEntry;
|
||||
|
||||
interface NominationEnsembleEntryController
|
||||
{
|
||||
public function index();
|
||||
|
||||
public function show(NominationEnsembleEntry $ensemble);
|
||||
|
||||
public function create();
|
||||
|
||||
public function store();
|
||||
|
||||
public function edit(NominationEnsembleEntry $ensemble);
|
||||
|
||||
public function update(NominationEnsembleEntry $ensemble);
|
||||
|
||||
public function destroy(NominationEnsembleEntry $ensemble);
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ class ScobdaNominationEnsembleController extends Controller implements Nominatio
|
|||
{
|
||||
$ensembles = NominationEnsemble::all();
|
||||
|
||||
return view('nomination_ensembles.scobda.index', compact('ensembles'));
|
||||
return view('nomination_ensembles.scobda.admin.ensembles.index', compact('ensembles'));
|
||||
}
|
||||
|
||||
public function show(NominationEnsemble $ensemble)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\NominationEnsembles;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\NominationEnsemble;
|
||||
use App\Models\NominationEnsembleEntry;
|
||||
use App\Models\School;
|
||||
use App\Models\Student;
|
||||
|
||||
class ScobdaNominationEnsembleEntryController extends Controller implements NominationEnsembleEntryController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$ensembles = NominationEnsemble::all();
|
||||
// populate an array with each ensemble id as a key. Each item will be a collection of students available to be nominated
|
||||
$availableStudents = [];
|
||||
// populate an array with each ensemble id as a key. Each item will be a collection of available instruments
|
||||
$availableInstruments = [];
|
||||
// populate an array with each ensemble id as a key. Each item will be a collection of nominationEntries already made
|
||||
$nominatedStudents = [];
|
||||
// an array of bool values with each ensemble id as a key. It will be true if additional nominations are available
|
||||
$nominationsAvailable = [];
|
||||
foreach ($ensembles as $ensemble) {
|
||||
// Gather a collection of students who may be nominated for this ensemble
|
||||
$availableStudents[$ensemble->id] = Student::where('grade', '<=', $ensemble->maximum_grade)
|
||||
->where('grade', '>=', $ensemble->minimum_grade)
|
||||
->where('school_id', auth()->user()->school_id)
|
||||
->orderBy('last_name')
|
||||
->orderBy('first_name')
|
||||
->get();
|
||||
$availableInstruments[$ensemble->id] = $ensemble->data['instruments'];
|
||||
$nominatedStudents[$ensemble->id] = $this->collapseNominations(auth()->user()->school, $ensemble,
|
||||
'nominations');
|
||||
|
||||
$nominatedStudentIds = [];
|
||||
|
||||
// Removed students already nominated from available students
|
||||
foreach ($nominatedStudents[$ensemble->id] as $nominatedStudent) {
|
||||
$nominatedStudentIds[] = $nominatedStudent->student_id;
|
||||
}
|
||||
$availableStudents[$ensemble->id] = $availableStudents[$ensemble->id]->reject(function ($student) use (
|
||||
$nominatedStudentIds
|
||||
) {
|
||||
return in_array($student->id, $nominatedStudentIds);
|
||||
});
|
||||
|
||||
$nominationsAvailable[$ensemble->id] = $ensemble->data['max_nominations'] > count($nominatedStudents[$ensemble->id]);
|
||||
|
||||
}
|
||||
|
||||
return view('nomination_ensembles.scobda.entries.index',
|
||||
compact('ensembles', 'availableStudents', 'availableInstruments', 'nominatedStudents', 'nominationsAvailable'));
|
||||
}
|
||||
|
||||
public function show(NominationEnsembleEntry $ensemble)
|
||||
{
|
||||
// TODO: Implement show() method.
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
// TODO: Implement create() method.
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$validData = request()->validate([
|
||||
'ensemble' => [
|
||||
'required',
|
||||
'exists:App\Models\NominationEnsemble,id',
|
||||
],
|
||||
'new_student' => [
|
||||
'required',
|
||||
'exists:App\Models\Student,id',
|
||||
],
|
||||
'new_instrument' => 'required',
|
||||
]);
|
||||
|
||||
if (NominationEnsembleEntry::where('student_id', $validData['new_student'])
|
||||
->where('nomination_ensemble_id', $validData['ensemble'])
|
||||
->count() > 0) {
|
||||
return redirect()->route('nomination.entry.index')->with('error',
|
||||
'Student already nominated for that ensemble');
|
||||
}
|
||||
|
||||
$proposedEnsemble = NominationEnsemble::find($validData['ensemble']);
|
||||
|
||||
if (! in_array($validData['new_instrument'], $proposedEnsemble->data['instruments'])) {
|
||||
return redirect()->route('nomination.entry.index')->with('error',
|
||||
'Invalid Instrument specified');
|
||||
}
|
||||
|
||||
$student = Student::find($validData['new_student']);
|
||||
$nextRank = $this->collapseNominations($student->school, $proposedEnsemble, 'next');
|
||||
if ($nextRank > $proposedEnsemble->data['max_nominations']) {
|
||||
return redirect()->route('nomination.entry.index')->with('error',
|
||||
'You have already used all of your nominations');
|
||||
}
|
||||
|
||||
$entry = new NominationEnsembleEntry();
|
||||
$entry->student_id = $validData['new_student'];
|
||||
$entry->nomination_ensemble_id = $validData['ensemble'];
|
||||
$data = [];
|
||||
$data['rank'] = $nextRank;
|
||||
$data['instrument'] = $validData['new_instrument'];
|
||||
$entry->data = $data;
|
||||
$entry->save();
|
||||
|
||||
return redirect()->route('nomination.entry.index')->with('success',
|
||||
'Nomination Recorded');
|
||||
}
|
||||
|
||||
public function edit(NominationEnsembleEntry $ensemble)
|
||||
{
|
||||
// TODO: Implement edit() method.
|
||||
}
|
||||
|
||||
public function update(NominationEnsembleEntry $ensemble)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
|
||||
public function destroy(NominationEnsembleEntry $ensemble)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a school and nomination ensemble, consolidate the rank valuek
|
||||
*
|
||||
* if returnType is next, the next available rank will be returned
|
||||
* if returnType is nominations, a collection of nominations will be returned
|
||||
*
|
||||
* @return int|array
|
||||
*
|
||||
* @var returnType = next|nominations
|
||||
*/
|
||||
private function collapseNominations(School $school, NominationEnsemble $ensemble, $returnType)
|
||||
{
|
||||
$nominations = $school->nominations()->get()->where('nomination_ensemble_id',
|
||||
$ensemble->id)->sortBy('data.rank');
|
||||
$n = 1;
|
||||
foreach ($nominations as $nomination) {
|
||||
$nomination->update(['data->rank' => $n]);
|
||||
$n++;
|
||||
}
|
||||
|
||||
if ($returnType == 'next') {
|
||||
return $n;
|
||||
}
|
||||
|
||||
return $nominations;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class NominationEnsemble extends Model
|
||||
{
|
||||
|
|
@ -15,4 +16,9 @@ class NominationEnsemble extends Model
|
|||
'data' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
public function entries(): HasMany
|
||||
{
|
||||
return $this->hasMany(NominationEnsembleEntry::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,28 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class NominationEnsembleEntry extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'data' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
protected function ensemble(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(NominationEnsemble::class);
|
||||
}
|
||||
|
||||
protected function student(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Student::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,4 +51,15 @@ class School extends Model
|
|||
'id',
|
||||
'id');
|
||||
}
|
||||
|
||||
public function nominations(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
NominationEnsembleEntry::class,
|
||||
Student::class,
|
||||
'school_id',
|
||||
'student_id',
|
||||
'id',
|
||||
'id');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ class Student extends Model
|
|||
];
|
||||
}
|
||||
|
||||
public function nominations(): HasMany
|
||||
{
|
||||
return $this->hasMany(NominationEnsembleEntry::class);
|
||||
}
|
||||
|
||||
public function school(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(School::class);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ use App\Actions\Tabulation\CalculateScoreSheetTotal;
|
|||
use App\Actions\Tabulation\CalculateScoreSheetTotalDivideByTotalWeights;
|
||||
use App\Actions\Tabulation\CalculateScoreSheetTotalDivideByWeightedPossible;
|
||||
use App\Http\Controllers\NominationEnsembles\NominationEnsembleController;
|
||||
use App\Http\Controllers\NominationEnsembles\NominationEnsembleEntryController;
|
||||
use App\Http\Controllers\NominationEnsembles\ScobdaNominationEnsembleController;
|
||||
use App\Http\Controllers\NominationEnsembles\ScobdaNominationEnsembleEntryController;
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Room;
|
||||
|
|
@ -63,7 +65,10 @@ class AppServiceProvider extends ServiceProvider
|
|||
$this->app->singleton(CreateEntry::class, CreateEntry::class);
|
||||
$this->app->singleton(UpdateEntry::class, UpdateEntry::class);
|
||||
$this->app->singleton(SetHeadDirector::class, SetHeadDirector::class);
|
||||
|
||||
// Nomination Ensemble
|
||||
$this->app->bind(NominationEnsembleController::class, ScobdaNominationEnsembleController::class);
|
||||
$this->app->bind(NominationEnsembleEntryController::class, ScobdaNominationEnsembleEntryController::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\NominationEnsembleEntry;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class NominationEnsembleEntryFactory extends Factory
|
||||
{
|
||||
protected $model = NominationEnsembleEntry::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'student_id' => $this->faker->randomNumber(),
|
||||
'nomination_ensemble_id' => $this->faker->randomNumber(),
|
||||
'data' => $this->faker->words(),
|
||||
'created_at' => Carbon::now(),
|
||||
'updated_at' => Carbon::now(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,9 @@
|
|||
@if(Auth::user()->school_id)
|
||||
<a href="{{route('students.index')}}" class="block p-2 hover:text-indigo-600">My Students</a>
|
||||
<a href="{{route('entries.index')}}" class="block p-2 hover:text-indigo-600">My Entries</a>
|
||||
@if(auditionSetting('nomination_ensemble_rules') !== 'disabled')
|
||||
<x-layout.navbar.menus.menu-item :href="route('nomination.entry.index')">My Nominations</x-layout.navbar.menus.menu-item>
|
||||
@endif
|
||||
<a href="{{route('doubler_request.index')}}" class="block p-2 hover:text-indigo-600">My Doubler Requests</a>
|
||||
<a href="{{route('my_school')}}" class="block p-2 hover:text-indigo-600">My School</a>
|
||||
@if(auditionSetting('invoicing_enabled'))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
@php($n=1)
|
||||
<x-layout.app>
|
||||
<x-slot:page_title>Nomination Entries</x-slot:page_title>
|
||||
|
||||
<x-layout.page-section-container>
|
||||
|
||||
@foreach($ensembles as $ensemble)
|
||||
<x-layout.page-section>
|
||||
<x-slot:section_name>{{ $ensemble->name }}</x-slot:section_name>
|
||||
<x-slot:section_description>{{ $ensemble->data['max_nominations'] }} nominations accepted</x-slot:section_description>
|
||||
<x-table.table>
|
||||
<thead>
|
||||
<tr>
|
||||
<x-table.th>Rank</x-table.th>
|
||||
<x-table.th>Student</x-table.th>
|
||||
<x-table.th>Instrument</x-table.th>
|
||||
</tr>
|
||||
</thead>
|
||||
<x-table.body>
|
||||
@foreach($nominatedStudents[$ensemble->id] as $nomination)
|
||||
<tr>
|
||||
<x-table.td>{{ $nomination->data['rank'] }}</x-table.td>
|
||||
<x-table.td>{{ $nomination->student->full_name() }}</x-table.td>
|
||||
<x-table.td>{{ $nomination->data['instrument'] }}</x-table.td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
{{-- LINE TO ADD A NOMINATION--}}
|
||||
@if($nominationsAvailable[$ensemble->id] && $availableStudents[$ensemble->id]->count() > 0)
|
||||
<tr>
|
||||
<x-form.form method="POST" action="{{ route('nomination.entry.store') }}">
|
||||
<input type="hidden" name="ensemble" value="{{ $ensemble->id }}"/>
|
||||
<x-table.th>NEW</x-table.th>
|
||||
<x-table.td>
|
||||
<x-form.select name="new_student">
|
||||
@foreach($availableStudents[$ensemble->id] as $student)
|
||||
<option value="{{$student->id}}">{{ $student->full_name() }}
|
||||
(Grade {{ $student->grade }})
|
||||
</option>
|
||||
@endforeach
|
||||
</x-form.select>
|
||||
</x-table.td>
|
||||
|
||||
<x-table.td>
|
||||
<x-form.select name="new_instrument">
|
||||
@foreach($availableInstruments[$ensemble->id] as $instrument)
|
||||
<option value="{{$instrument}}">{{$instrument}}</option>
|
||||
@endforeach
|
||||
</x-form.select>
|
||||
</x-table.td>
|
||||
|
||||
<x-table.td>
|
||||
<x-form.button class="bg-green-800">Add</x-form.button>
|
||||
</x-table.td>
|
||||
</x-form.form>
|
||||
</tr>
|
||||
@endif
|
||||
</x-table.body>
|
||||
</x-table.table>
|
||||
|
||||
</x-layout.page-section>
|
||||
@endforeach
|
||||
|
||||
</x-layout.page-section-container>
|
||||
|
||||
</x-layout.app>
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\NominationEnsembles\NominationEnsembleController;
|
||||
use App\Http\Controllers\NominationEnsembles\NominationEnsembleEntryController;
|
||||
use App\Http\Middleware\CheckIfAdmin;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -14,5 +15,8 @@ Route::middleware(['auth', 'verified', CheckIfAdmin::class])->prefix('nomination
|
|||
});
|
||||
|
||||
Route::middleware(['auth', 'verified'])->prefix('nominations/')->group(function () {
|
||||
|
||||
Route::controller(NominationEnsembleEntryController::class)->group(function () {
|
||||
Route::get('/', 'index')->name('nomination.entry.index');
|
||||
Route::post('/', 'store')->name('nomination.entry.store');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue