Files
unsupervised-scheduler/src/Data/AvailabilityRepository.php
James Griffin 0fbafc9d18
Some checks failed
CI / Coding Standards (push) Failing after 2m31s
CI / PHPStan (push) Failing after 50s
CI / Tests (PHP 8.1) (push) Successful in 50s
CI / Tests (PHP 8.2) (push) Successful in 48s
CI / Tests (PHP 8.3) (push) Successful in 40s
CI / No Debug Code (push) Successful in 2s
Initial plugin scaffold: lesson scheduling WordPress plugin
- Custom DB tables for availability slots and lesson bookings
- Instructor (wp-admin) and student (front-end) roles with custom capabilities
- REST API under us-scheduler/v1 for availability CRUD and booking
- [us_booking] and [us_student_login] shortcodes for student front end
- PHPUnit + Brain\Monkey unit test suite (29 tests)
- Gitea Actions CI: lint, PHPStan, tests on PHP 8.1/8.2/8.3, no-debug check
- Feature docs under docs/features/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 12:44:46 -03:00

118 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Unsupervised\Schedular\Data;
use Unsupervised\Schedular\Model\AvailabilitySlot;
class AvailabilityRepository
{
private string $table;
public function __construct(private \wpdb $db)
{
$this->table = $db->prefix . 'us_availability';
}
public function insert(AvailabilitySlot $slot): int
{
$this->db->insert(
$this->table,
[
'instructor_id' => $slot->instructorId,
'start_dt' => $slot->startDt,
'end_dt' => $slot->endDt,
'is_booked' => 0,
'created_at' => current_time('mysql'),
],
['%d', '%s', '%s', '%d', '%s']
);
return $this->db->insert_id;
}
/**
* Find unbooked slots, optionally filtered by instructor and date range.
*
* @return list<AvailabilitySlot>
*/
public function findAvailable(int $instructorId = 0, string $from = '', string $to = ''): array
{
$where = ['is_booked = 0'];
$params = [];
if ($instructorId > 0) {
$where[] = 'instructor_id = %d';
$params[] = $instructorId;
}
if ($from !== '') {
$where[] = 'start_dt >= %s';
$params[] = $from;
}
if ($to !== '') {
$where[] = 'end_dt <= %s';
$params[] = $to;
}
$whereClause = implode(' AND ', $where);
$sql = "SELECT * FROM {$this->table} WHERE {$whereClause} ORDER BY start_dt ASC";
$rows = $params
? $this->db->get_results($this->db->prepare($sql, $params))
: $this->db->get_results($sql);
return array_map(AvailabilitySlot::fromRow(...), $rows ?? []);
}
/**
* Find all slots for an instructor (booked and unbooked).
*
* @return list<AvailabilitySlot>
*/
public function findByInstructor(int $instructorId): array
{
$rows = $this->db->get_results(
$this->db->prepare(
"SELECT * FROM {$this->table} WHERE instructor_id = %d ORDER BY start_dt ASC",
$instructorId
)
);
return array_map(AvailabilitySlot::fromRow(...), $rows ?? []);
}
public function findById(int $id): ?AvailabilitySlot
{
$row = $this->db->get_row(
$this->db->prepare("SELECT * FROM {$this->table} WHERE id = %d", $id)
);
return $row ? AvailabilitySlot::fromRow($row) : null;
}
public function markBooked(int $id): bool
{
return (bool) $this->db->update(
$this->table,
['is_booked' => 1],
['id' => $id],
['%d'],
['%d']
);
}
/**
* Delete an unbooked slot. Returns false if the slot is already booked.
*/
public function delete(int $id): bool
{
return (bool) $this->db->delete(
$this->table,
['id' => $id, 'is_booked' => 0],
['%d', '%d']
);
}
}