Backup: old custom PHP API code removed from fahrschultermin.de
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
final class AppointmentRepository extends BaseRepository
|
||||
{
|
||||
public function listForTenant(int $tenantId, string $from, string $to, ?int $instructorId = null): array
|
||||
{
|
||||
$sql = 'SELECT a.*, s.first_name AS student_first_name, s.last_name AS student_last_name, s.needs_glasses AS student_needs_glasses,
|
||||
i.first_name AS instructor_first_name, i.last_name AS instructor_last_name,
|
||||
lt.name AS lesson_type_name, lt.color AS lesson_type_color, lt.is_rest_relevant, lt.allows_student, lt.category AS lesson_type_category,
|
||||
(
|
||||
SELECT au.requirement_key
|
||||
FROM appointment_units au
|
||||
WHERE au.appointment_id = a.id
|
||||
ORDER BY au.id
|
||||
LIMIT 1
|
||||
) AS counted_requirement_key
|
||||
FROM appointments a
|
||||
JOIN instructors i ON i.id = a.instructor_id
|
||||
LEFT JOIN students s ON s.id = a.student_id
|
||||
JOIN lesson_types lt ON lt.id = a.lesson_type_id
|
||||
WHERE a.tenant_id = :tenant_id
|
||||
AND a.start_at < :to
|
||||
AND a.end_at > :from';
|
||||
$params = [
|
||||
'tenant_id' => $tenantId,
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
];
|
||||
|
||||
if ($instructorId !== null) {
|
||||
$sql .= ' AND a.instructor_id = :instructor_id';
|
||||
$params['instructor_id'] = $instructorId;
|
||||
}
|
||||
|
||||
$sql .= ' ORDER BY a.start_at';
|
||||
$statement = $this->db->prepare($sql);
|
||||
$statement->execute($params);
|
||||
|
||||
return $statement->fetchAll();
|
||||
}
|
||||
|
||||
public function find(int $tenantId, int $id): ?array
|
||||
{
|
||||
$statement = $this->db->prepare('SELECT * FROM appointments WHERE tenant_id = :tenant_id AND id = :id');
|
||||
$statement->execute(['tenant_id' => $tenantId, 'id' => $id]);
|
||||
$appointment = $statement->fetch() ?: null;
|
||||
|
||||
if ($appointment !== null) {
|
||||
$appointment['units_breakdown'] = $this->units((int) $appointment['id']);
|
||||
}
|
||||
|
||||
return $appointment;
|
||||
}
|
||||
|
||||
public function create(int $tenantId, array $data, int $actorId): array
|
||||
{
|
||||
$timestamp = $this->now();
|
||||
$statement = $this->db->prepare(
|
||||
'INSERT INTO appointments
|
||||
(tenant_id, student_id, instructor_id, lesson_type_id, title, category, start_at, end_at, units, status, notes, notes_private, warning_acknowledged, created_by, updated_by, created_at, updated_at)
|
||||
VALUES
|
||||
(:tenant_id, :student_id, :instructor_id, :lesson_type_id, :title, :category, :start_at, :end_at, :units, :status, :notes, :notes_private, :warning_acknowledged, :created_by, :updated_by, :created_at, :updated_at)'
|
||||
);
|
||||
$statement->execute([
|
||||
'tenant_id' => $tenantId,
|
||||
'student_id' => $data['student_id'] ?: null,
|
||||
'instructor_id' => $data['instructor_id'],
|
||||
'lesson_type_id' => $data['lesson_type_id'],
|
||||
'title' => $data['title'],
|
||||
'category' => $data['category'],
|
||||
'start_at' => $data['start_at'],
|
||||
'end_at' => $data['end_at'],
|
||||
'units' => (int) $data['units'],
|
||||
'status' => $data['status'],
|
||||
'notes' => $data['notes'] ?? '',
|
||||
'notes_private' => $data['notes_private'] ?? '',
|
||||
'warning_acknowledged' => !empty($data['warning_acknowledged']) ? 1 : 0,
|
||||
'created_by' => $actorId,
|
||||
'updated_by' => $actorId,
|
||||
'created_at' => $timestamp,
|
||||
'updated_at' => $timestamp,
|
||||
]);
|
||||
|
||||
$appointmentId = (int) $this->lastInsertId();
|
||||
$this->replaceUnits($appointmentId, $data['units_breakdown'] ?? []);
|
||||
|
||||
return $this->find($tenantId, $appointmentId);
|
||||
}
|
||||
|
||||
public function update(int $tenantId, int $id, array $data, int $actorId): ?array
|
||||
{
|
||||
$statement = $this->db->prepare(
|
||||
'UPDATE appointments
|
||||
SET student_id = :student_id, instructor_id = :instructor_id, lesson_type_id = :lesson_type_id,
|
||||
title = :title, category = :category, start_at = :start_at, end_at = :end_at, units = :units,
|
||||
status = :status, notes = :notes, notes_private = :notes_private, warning_acknowledged = :warning_acknowledged,
|
||||
updated_by = :updated_by, updated_at = :updated_at
|
||||
WHERE tenant_id = :tenant_id AND id = :id'
|
||||
);
|
||||
$statement->execute([
|
||||
'tenant_id' => $tenantId,
|
||||
'id' => $id,
|
||||
'student_id' => $data['student_id'] ?: null,
|
||||
'instructor_id' => $data['instructor_id'],
|
||||
'lesson_type_id' => $data['lesson_type_id'],
|
||||
'title' => $data['title'],
|
||||
'category' => $data['category'],
|
||||
'start_at' => $data['start_at'],
|
||||
'end_at' => $data['end_at'],
|
||||
'units' => (int) $data['units'],
|
||||
'status' => $data['status'],
|
||||
'notes' => $data['notes'] ?? '',
|
||||
'notes_private' => $data['notes_private'] ?? '',
|
||||
'warning_acknowledged' => !empty($data['warning_acknowledged']) ? 1 : 0,
|
||||
'updated_by' => $actorId,
|
||||
'updated_at' => $this->now(),
|
||||
]);
|
||||
|
||||
$this->replaceUnits($id, $data['units_breakdown'] ?? []);
|
||||
|
||||
return $this->find($tenantId, $id);
|
||||
}
|
||||
|
||||
public function delete(int $tenantId, int $id): void
|
||||
{
|
||||
$statement = $this->db->prepare('DELETE FROM appointments WHERE tenant_id = :tenant_id AND id = :id');
|
||||
$statement->execute(['tenant_id' => $tenantId, 'id' => $id]);
|
||||
}
|
||||
|
||||
public function units(int $appointmentId): array
|
||||
{
|
||||
$statement = $this->db->prepare('SELECT * FROM appointment_units WHERE appointment_id = :appointment_id');
|
||||
$statement->execute(['appointment_id' => $appointmentId]);
|
||||
|
||||
return $statement->fetchAll();
|
||||
}
|
||||
|
||||
public function overlappingForInstructor(int $tenantId, int $instructorId, string $from, string $to, ?int $ignoreId = null): array
|
||||
{
|
||||
$sql = 'SELECT * FROM appointments
|
||||
WHERE tenant_id = :tenant_id AND instructor_id = :instructor_id
|
||||
AND start_at < :to AND end_at > :from';
|
||||
$params = [
|
||||
'tenant_id' => $tenantId,
|
||||
'instructor_id' => $instructorId,
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
];
|
||||
|
||||
if ($ignoreId !== null) {
|
||||
$sql .= ' AND id != :ignore_id';
|
||||
$params['ignore_id'] = $ignoreId;
|
||||
}
|
||||
|
||||
$statement = $this->db->prepare($sql);
|
||||
$statement->execute($params);
|
||||
|
||||
return $statement->fetchAll();
|
||||
}
|
||||
|
||||
public function overlappingForStudent(int $tenantId, int $studentId, string $from, string $to, ?int $ignoreId = null): array
|
||||
{
|
||||
$sql = 'SELECT * FROM appointments
|
||||
WHERE tenant_id = :tenant_id AND student_id = :student_id
|
||||
AND start_at < :to AND end_at > :from';
|
||||
$params = [
|
||||
'tenant_id' => $tenantId,
|
||||
'student_id' => $studentId,
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
];
|
||||
|
||||
if ($ignoreId !== null) {
|
||||
$sql .= ' AND id != :ignore_id';
|
||||
$params['ignore_id'] = $ignoreId;
|
||||
}
|
||||
|
||||
$statement = $this->db->prepare($sql);
|
||||
$statement->execute($params);
|
||||
|
||||
return $statement->fetchAll();
|
||||
}
|
||||
|
||||
public function lastRestRelevantForInstructor(int $tenantId, int $instructorId, string $beforeStart, ?int $ignoreId = null): ?array
|
||||
{
|
||||
$sql = 'SELECT a.*, lt.name AS lesson_type_name
|
||||
FROM appointments a
|
||||
JOIN lesson_types lt ON lt.id = a.lesson_type_id
|
||||
WHERE a.tenant_id = :tenant_id
|
||||
AND a.instructor_id = :instructor_id
|
||||
AND lt.is_rest_relevant = 1
|
||||
AND a.end_at <= :before_start';
|
||||
$params = [
|
||||
'tenant_id' => $tenantId,
|
||||
'instructor_id' => $instructorId,
|
||||
'before_start' => $beforeStart,
|
||||
];
|
||||
|
||||
if ($ignoreId !== null) {
|
||||
$sql .= ' AND a.id != :ignore_id';
|
||||
$params['ignore_id'] = $ignoreId;
|
||||
}
|
||||
|
||||
$sql .= ' ORDER BY a.end_at DESC LIMIT 1';
|
||||
$statement = $this->db->prepare($sql);
|
||||
$statement->execute($params);
|
||||
|
||||
return $statement->fetch() ?: null;
|
||||
}
|
||||
|
||||
public function hasRestRelevantAfterStartOnDay(int $tenantId, int $instructorId, string $dayStart, string $dayEnd, string $startAt): bool
|
||||
{
|
||||
$statement = $this->db->prepare(
|
||||
'SELECT 1
|
||||
FROM appointments a
|
||||
JOIN lesson_types lt ON lt.id = a.lesson_type_id
|
||||
WHERE a.tenant_id = :tenant_id
|
||||
AND a.instructor_id = :instructor_id
|
||||
AND lt.is_rest_relevant = 1
|
||||
AND a.start_at < :day_end
|
||||
AND a.end_at > :day_start
|
||||
AND a.end_at > :start_at
|
||||
LIMIT 1'
|
||||
);
|
||||
$statement->execute([
|
||||
'tenant_id' => $tenantId,
|
||||
'instructor_id' => $instructorId,
|
||||
'day_start' => $dayStart,
|
||||
'day_end' => $dayEnd,
|
||||
'start_at' => $startAt,
|
||||
]);
|
||||
|
||||
return (bool) $statement->fetchColumn();
|
||||
}
|
||||
|
||||
public function nextForTenant(int $tenantId, string $from, ?int $instructorId = null): ?array
|
||||
{
|
||||
$sql = 'SELECT a.*, s.first_name AS student_first_name, s.last_name AS student_last_name,
|
||||
i.first_name AS instructor_first_name, i.last_name AS instructor_last_name,
|
||||
lt.name AS lesson_type_name
|
||||
FROM appointments a
|
||||
JOIN instructors i ON i.id = a.instructor_id
|
||||
LEFT JOIN students s ON s.id = a.student_id
|
||||
JOIN lesson_types lt ON lt.id = a.lesson_type_id
|
||||
WHERE a.tenant_id = :tenant_id
|
||||
AND a.start_at >= :from';
|
||||
$params = [
|
||||
'tenant_id' => $tenantId,
|
||||
'from' => $from,
|
||||
];
|
||||
|
||||
if ($instructorId !== null) {
|
||||
$sql .= ' AND a.instructor_id = :instructor_id';
|
||||
$params['instructor_id'] = $instructorId;
|
||||
}
|
||||
|
||||
$sql .= ' ORDER BY a.start_at ASC LIMIT 1';
|
||||
$statement = $this->db->prepare($sql);
|
||||
$statement->execute($params);
|
||||
|
||||
return $statement->fetch() ?: null;
|
||||
}
|
||||
|
||||
private function replaceUnits(int $appointmentId, array $rows): void
|
||||
{
|
||||
$delete = $this->db->prepare('DELETE FROM appointment_units WHERE appointment_id = :appointment_id');
|
||||
$delete->execute(['appointment_id' => $appointmentId]);
|
||||
|
||||
$insert = $this->db->prepare(
|
||||
'INSERT INTO appointment_units (appointment_id, requirement_key, label, units_counted, created_at)
|
||||
VALUES (:appointment_id, :requirement_key, :label, :units_counted, :created_at)'
|
||||
);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if ((int) ($row['units_counted'] ?? 0) <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$insert->execute([
|
||||
'appointment_id' => $appointmentId,
|
||||
'requirement_key' => $row['requirement_key'] ?? null,
|
||||
'label' => $row['label'] ?? null,
|
||||
'units_counted' => (int) $row['units_counted'],
|
||||
'created_at' => $this->now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user