feat: Permettre à l'élève de consulter ses notes et moyennes
L'élève avait accès à ses compétences mais pas à ses notes numériques. Cette fonctionnalité lui donne une vue complète de sa progression scolaire avec moyennes par matière, détail par évaluation, statistiques de classe, et un mode "découverte" pour révéler ses notes à son rythme (FR14, FR15). Les notes ne sont visibles qu'après publication par l'enseignant, ce qui garantit que l'élève les découvre avant ses parents (délai 24h story 6.7).
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Scolarite\Infrastructure\Api\Provider;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Administration\Domain\Model\User\Role;
|
||||
use App\Administration\Infrastructure\Security\SecurityUser;
|
||||
use App\Scolarite\Infrastructure\Api\Resource\StudentGradeResource;
|
||||
use App\Shared\Infrastructure\Tenant\TenantContext;
|
||||
|
||||
use function array_map;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
|
||||
use Override;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
|
||||
/**
|
||||
* @implements ProviderInterface<StudentGradeResource>
|
||||
*/
|
||||
final readonly class StudentGradeCollectionProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private Connection $connection,
|
||||
private TenantContext $tenantContext,
|
||||
private Security $security,
|
||||
) {
|
||||
}
|
||||
|
||||
/** @return list<StudentGradeResource> */
|
||||
#[Override]
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
||||
{
|
||||
if (!$this->tenantContext->hasTenant()) {
|
||||
throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
|
||||
}
|
||||
|
||||
$user = $this->security->getUser();
|
||||
|
||||
if (!$user instanceof SecurityUser) {
|
||||
throw new UnauthorizedHttpException('Bearer', 'Authentification requise.');
|
||||
}
|
||||
|
||||
if (!in_array(Role::ELEVE->value, $user->getRoles(), true)) {
|
||||
throw new AccessDeniedHttpException('Accès réservé aux élèves.');
|
||||
}
|
||||
|
||||
$tenantId = (string) $this->tenantContext->getCurrentTenantId();
|
||||
$studentId = $user->userId();
|
||||
|
||||
/** @var string|null $subjectId */
|
||||
$subjectId = $uriVariables['subjectId'] ?? null;
|
||||
|
||||
if (is_string($subjectId) && $subjectId === '') {
|
||||
$subjectId = null;
|
||||
}
|
||||
|
||||
$subjectFilter = $subjectId !== null ? 'AND s.id = :subject_id' : '';
|
||||
|
||||
$rows = $this->connection->fetchAllAssociative(
|
||||
"SELECT g.id AS grade_id, g.value, g.status AS grade_status, g.appreciation,
|
||||
e.id AS evaluation_id, e.title AS evaluation_title,
|
||||
e.evaluation_date, e.grade_scale, e.coefficient,
|
||||
e.grades_published_at,
|
||||
s.id AS subject_id, s.name AS subject_name,
|
||||
es.average AS class_average, es.min_grade AS class_min, es.max_grade AS class_max
|
||||
FROM grades g
|
||||
JOIN evaluations e ON g.evaluation_id = e.id
|
||||
JOIN subjects s ON e.subject_id = s.id
|
||||
LEFT JOIN evaluation_statistics es ON es.evaluation_id = e.id
|
||||
WHERE g.student_id = :student_id
|
||||
AND g.tenant_id = :tenant_id
|
||||
AND e.grades_published_at IS NOT NULL
|
||||
AND e.status != :deleted_status
|
||||
{$subjectFilter}
|
||||
ORDER BY e.evaluation_date DESC, e.created_at DESC",
|
||||
$subjectId !== null
|
||||
? ['student_id' => $studentId, 'tenant_id' => $tenantId, 'deleted_status' => 'deleted', 'subject_id' => $subjectId]
|
||||
: ['student_id' => $studentId, 'tenant_id' => $tenantId, 'deleted_status' => 'deleted'],
|
||||
);
|
||||
|
||||
return array_map(self::hydrateResource(...), $rows);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $row */
|
||||
private static function hydrateResource(array $row): StudentGradeResource
|
||||
{
|
||||
$resource = new StudentGradeResource();
|
||||
|
||||
/** @var string $gradeId */
|
||||
$gradeId = $row['grade_id'];
|
||||
$resource->id = $gradeId;
|
||||
|
||||
/** @var string $evaluationId */
|
||||
$evaluationId = $row['evaluation_id'];
|
||||
$resource->evaluationId = $evaluationId;
|
||||
|
||||
/** @var string $evaluationTitle */
|
||||
$evaluationTitle = $row['evaluation_title'];
|
||||
$resource->evaluationTitle = $evaluationTitle;
|
||||
|
||||
/** @var string $evaluationDate */
|
||||
$evaluationDate = $row['evaluation_date'];
|
||||
$resource->evaluationDate = $evaluationDate;
|
||||
|
||||
/** @var string|int $gradeScale */
|
||||
$gradeScale = $row['grade_scale'];
|
||||
$resource->gradeScale = (int) $gradeScale;
|
||||
|
||||
/** @var string|float $coefficient */
|
||||
$coefficient = $row['coefficient'];
|
||||
$resource->coefficient = (float) $coefficient;
|
||||
|
||||
/** @var string $subjectIdVal */
|
||||
$subjectIdVal = $row['subject_id'];
|
||||
$resource->subjectId = $subjectIdVal;
|
||||
|
||||
/** @var string|null $subjectName */
|
||||
$subjectName = $row['subject_name'];
|
||||
$resource->subjectName = $subjectName;
|
||||
|
||||
/** @var string|float|null $value */
|
||||
$value = $row['value'];
|
||||
$resource->value = $value !== null ? (float) $value : null;
|
||||
|
||||
/** @var string $gradeStatus */
|
||||
$gradeStatus = $row['grade_status'];
|
||||
$resource->status = $gradeStatus;
|
||||
|
||||
/** @var string|null $appreciation */
|
||||
$appreciation = $row['appreciation'];
|
||||
$resource->appreciation = $appreciation;
|
||||
|
||||
/** @var string|null $publishedAt */
|
||||
$publishedAt = $row['grades_published_at'];
|
||||
$resource->publishedAt = $publishedAt;
|
||||
|
||||
/** @var string|float|null $classAverage */
|
||||
$classAverage = $row['class_average'];
|
||||
$resource->classAverage = $classAverage !== null ? (float) $classAverage : null;
|
||||
|
||||
/** @var string|float|null $classMin */
|
||||
$classMin = $row['class_min'];
|
||||
$resource->classMin = $classMin !== null ? (float) $classMin : null;
|
||||
|
||||
/** @var string|float|null $classMax */
|
||||
$classMax = $row['class_max'];
|
||||
$resource->classMax = $classMax !== null ? (float) $classMax : null;
|
||||
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user