Permet aux administrateurs de désigner un enseignant remplaçant pour un autre enseignant absent, sur des classes et matières précises, pour une période donnée. Le dashboard enseignant affiche les remplacements actifs avec les noms de classes/matières au lieu des identifiants bruts. Inclut les corrections de la code review : - Requête findActiveByTenant qui excluait les remplacements en cours mais incluait les futurs (manquait start_date <= :at) - Validation tenant et rôle enseignant dans le handler de désignation pour empêcher l'affectation cross-tenant ou de non-enseignants - Validation structurée du payload classes (Assert\Collection + UUID) pour éviter les erreurs serveur sur payloads malformés - API replaced-classes enrichie avec les noms classe/matière
68 lines
2.8 KiB
PHP
68 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace DoctrineMigrations;
|
|
|
|
use Doctrine\DBAL\Schema\Schema;
|
|
use Doctrine\Migrations\AbstractMigration;
|
|
|
|
/**
|
|
* Creates the teacher_replacements and replacement_classes tables for Story 2.9.
|
|
*
|
|
* Models temporary teacher replacement: an admin designates a replacement teacher
|
|
* with start/end dates for specific class/subject pairs.
|
|
*/
|
|
final class Version20260215100000 extends AbstractMigration
|
|
{
|
|
public function getDescription(): string
|
|
{
|
|
return 'Create teacher_replacements and replacement_classes tables (Story 2.9)';
|
|
}
|
|
|
|
public function up(Schema $schema): void
|
|
{
|
|
$this->addSql(<<<'SQL'
|
|
CREATE TABLE IF NOT EXISTS teacher_replacements (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL,
|
|
replaced_teacher_id UUID NOT NULL,
|
|
replacement_teacher_id UUID NOT NULL,
|
|
start_date DATE NOT NULL,
|
|
end_date DATE NOT NULL,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'active',
|
|
reason TEXT,
|
|
created_by UUID NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
ended_at TIMESTAMPTZ,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT valid_dates CHECK (end_date >= start_date),
|
|
CONSTRAINT different_teachers CHECK (replaced_teacher_id != replacement_teacher_id)
|
|
)
|
|
SQL);
|
|
|
|
$this->addSql(<<<'SQL'
|
|
CREATE TABLE IF NOT EXISTS replacement_classes (
|
|
replacement_id UUID NOT NULL REFERENCES teacher_replacements(id) ON DELETE CASCADE,
|
|
class_id UUID NOT NULL,
|
|
subject_id UUID NOT NULL,
|
|
PRIMARY KEY (replacement_id, class_id, subject_id)
|
|
)
|
|
SQL);
|
|
|
|
$this->addSql('CREATE INDEX idx_replacements_tenant ON teacher_replacements(tenant_id)');
|
|
$this->addSql('CREATE INDEX idx_replacements_dates ON teacher_replacements(start_date, end_date)');
|
|
$this->addSql('CREATE INDEX idx_replacements_status ON teacher_replacements(status)');
|
|
$this->addSql('CREATE INDEX idx_replacements_replaced_teacher ON teacher_replacements(replaced_teacher_id)');
|
|
$this->addSql('CREATE INDEX idx_replacements_replacement_teacher ON teacher_replacements(replacement_teacher_id)');
|
|
$this->addSql('CREATE INDEX idx_replacements_tenant_status ON teacher_replacements(tenant_id, status)');
|
|
$this->addSql('CREATE INDEX idx_replacements_status_end_date ON teacher_replacements(status, end_date)');
|
|
}
|
|
|
|
public function down(Schema $schema): void
|
|
{
|
|
$this->addSql('DROP TABLE IF EXISTS replacement_classes');
|
|
$this->addSql('DROP TABLE IF EXISTS teacher_replacements');
|
|
}
|
|
}
|