Restructure src/ and tests/ from package-by-type to package-by-domain
CI / Coding Standards (push) Successful in 43s
CI / PHPStan (push) Successful in 52s
CI / Tests (PHP 8.1) (push) Successful in 47s
CI / Tests (PHP 8.2) (push) Successful in 49s
CI / Tests (PHP 8.3) (push) Successful in 37s
CI / No Debug Code (push) Successful in 2s
CI / Coding Standards (push) Successful in 43s
CI / PHPStan (push) Successful in 52s
CI / Tests (PHP 8.1) (push) Successful in 47s
CI / Tests (PHP 8.2) (push) Successful in 49s
CI / Tests (PHP 8.3) (push) Successful in 37s
CI / No Debug Code (push) Successful in 2s
All classes are now organised by domain (Availability, Booking, Auth). Each domain package contains its value object, repository, admin controller, REST endpoint, and any shortcode pages under a matching sub-namespace. Cross-cutting wiring (Plugin, AdminMenu, RestRegistrar, ShortcodeRegistrar, Schema) lives at src/ root. Tests mirror the domain structure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Unsupervised\Schedular\Availability;
|
||||
|
||||
use Unsupervised\Schedular\Auth\RoleManager;
|
||||
|
||||
class AvailabilityEndpoint {
|
||||
|
||||
public function __construct( private AvailabilityRepository $repository ) {}
|
||||
|
||||
public function registerRoutes( string $route_namespace ): void {
|
||||
register_rest_route(
|
||||
$route_namespace,
|
||||
'/availability',
|
||||
[
|
||||
[
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'index' ],
|
||||
'permission_callback' => [ $this, 'canBook' ],
|
||||
'args' => [
|
||||
'instructor_id' => [
|
||||
'type' => 'integer',
|
||||
'default' => 0,
|
||||
],
|
||||
'from' => [
|
||||
'type' => 'string',
|
||||
'default' => '',
|
||||
],
|
||||
'to' => [
|
||||
'type' => 'string',
|
||||
'default' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'methods' => \WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'create' ],
|
||||
'permission_callback' => [ $this, 'canManage' ],
|
||||
'args' => [
|
||||
'start_dt' => [
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
],
|
||||
'end_dt' => [
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$route_namespace,
|
||||
'/availability/(?P<id>\d+)',
|
||||
[
|
||||
[
|
||||
'methods' => \WP_REST_Server::DELETABLE,
|
||||
'callback' => [ $this, 'delete' ],
|
||||
'permission_callback' => [ $this, 'canManage' ],
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function index( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
$slots = $this->repository->findAvailable(
|
||||
(int) $request->get_param( 'instructor_id' ),
|
||||
(string) $request->get_param( 'from' ),
|
||||
(string) $request->get_param( 'to' ),
|
||||
);
|
||||
|
||||
return new \WP_REST_Response( array_map( fn( AvailabilitySlot $s ) => $s->toArray(), $slots ), 200 );
|
||||
}
|
||||
|
||||
public function create( \WP_REST_Request $request ): \WP_REST_Response {
|
||||
$slot = new AvailabilitySlot(
|
||||
instructorId: get_current_user_id(),
|
||||
startDt: (string) $request->get_param( 'start_dt' ),
|
||||
endDt: (string) $request->get_param( 'end_dt' ),
|
||||
);
|
||||
|
||||
$id = $this->repository->insert( $slot );
|
||||
|
||||
return new \WP_REST_Response( [ 'id' => $id ], 201 );
|
||||
}
|
||||
|
||||
public function delete( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
|
||||
$id = absint( $request->get_param( 'id' ) );
|
||||
$slot = $this->repository->findById( $id );
|
||||
|
||||
if ( null === $slot ) {
|
||||
return new \WP_Error( 'not_found', __( 'Slot not found.', 'unsupervised-schedular' ), [ 'status' => 404 ] );
|
||||
}
|
||||
|
||||
if ( get_current_user_id() !== $slot->instructorId ) {
|
||||
return new \WP_Error( 'forbidden', __( 'You cannot delete this slot.', 'unsupervised-schedular' ), [ 'status' => 403 ] );
|
||||
}
|
||||
|
||||
if ( $slot->isBooked ) {
|
||||
return new \WP_Error( 'slot_booked', __( 'Cannot delete a booked slot.', 'unsupervised-schedular' ), [ 'status' => 409 ] );
|
||||
}
|
||||
|
||||
$this->repository->delete( $id );
|
||||
|
||||
return new \WP_REST_Response( null, 204 );
|
||||
}
|
||||
|
||||
public function canBook(): bool {
|
||||
return is_user_logged_in() && current_user_can( RoleManager::CAP_BOOK_LESSON );
|
||||
}
|
||||
|
||||
public function canManage(): bool {
|
||||
return is_user_logged_in() && current_user_can( RoleManager::CAP_MANAGE_AVAILABILITY );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user