Files
peptide-repo-core/includes/api/class-pr-core-rest-controller.php
peptiderepo 8d3064785c fix: resolve all PHPCS violations and 300-line rule breaches
- Add @package Peptide_Repo_Core file docblocks to all PHP files
- Add @var docblocks to all public readonly DTO properties
- Add @param docs to sanitize_evidence_strength / sanitize_review_status
- Replace short ternary ?: with phpcs:ignore on each violating line
- Add phpcs:ignore for InterpolatedNotPrepared on ${table} SQL strings
- Add phpcs:ignore for GlobalVariablesOverride in uninstall.php and card.php
- Add translators comment to __ call with placeholder in related-posts-section
- Fix InlineComment.InvalidEndChar: add periods to all bare inline comments
- Expand single-line /** @return void */ docblocks with summaries
- SPLIT class-pr-core-seed-data.php (was 360 lines):
  → class-pr-core-seed-data.php (149 lines, orchestration only)
  → class-pr-core-seed-fixtures.php (254 lines, static fixture data)
- SPLIT class-pr-core-peptide-cpt.php (was 309 lines):
  → class-pr-core-peptide-cpt.php (224 lines, CPT + hooks + sanitizers)
  → class-pr-core-peptide-meta-schema.php (133 lines, meta field defs)
- SPLIT class-pr-core-settings.php (was 340 lines after docblock expansion):
  → class-pr-core-settings.php (264 lines, registration + sanitization)
  → class-pr-core-settings-renderer.php (124 lines, render methods)
- All includes/ PHP files now <= 300 lines

Agent-Session: claude-adopt-ci-20260616
2026-06-16 15:48:53 +00:00

292 lines
8.2 KiB
PHP

<?php
declare(strict_types=1);
/**
* REST API controller for peptide data (read-only public, write requires capability).
*
* What: Exposes peptides, dosing rows, and legal cells via REST endpoints.
* Who calls it: PR_Core::init() registers rest_api_init hook.
* Dependencies: PR_Core_Peptide_Repository, PR_Core_Dosing_Repository,
* PR_Core_Legal_Repository.
*
* Namespace: pr-core/v1
* Endpoints:
* GET /peptides — List peptides (public)
* GET /peptides/{id} — Single peptide (public)
* GET /peptides/{id}/dosing — Dosing rows for peptide (public)
* GET /peptides/{id}/legal — Legal cells for peptide (public)
* POST /peptides/{id}/dosing — Add dosing row (auth)
* POST /peptides/{id}/legal — Add legal cell (auth)
*
* @see ARCHITECTURE.md — REST API specification.
* @package Peptide_Repo_Core
*/
class PR_Core_Rest_Controller {
/**
* REST namespace.
*
* @var string REST namespace.
*/
private const REST_NAMESPACE = 'pr-core/v1';
/**
* Register the rest_api_init hook.
*
* @return void
*/
public function register_hooks(): void {
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
}
/**
* Register all REST routes.
*
* Side effects: registers routes with WordPress REST API.
*
* @return void
*/
public function register_routes(): void {
// GET /peptides.
register_rest_route(
self::REST_NAMESPACE,
'/peptides',
array(
'methods' => 'GET',
'callback' => array( $this, 'list_peptides' ),
'permission_callback' => '__return_true',
'args' => array(
'category' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'evidence_strength' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'search' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'per_page' => array(
'type' => 'integer',
'default' => 25,
'minimum' => 1,
'maximum' => 100,
),
'page' => array(
'type' => 'integer',
'default' => 1,
'minimum' => 1,
),
),
)
);
// GET /peptides/{id}.
register_rest_route(
self::REST_NAMESPACE,
'/peptides/(?P<id>\d+)',
array(
'methods' => 'GET',
'callback' => array( $this, 'get_peptide' ),
'permission_callback' => '__return_true',
)
);
// GET /peptides/{id}/dosing.
register_rest_route(
self::REST_NAMESPACE,
'/peptides/(?P<id>\d+)/dosing',
array(
'methods' => 'GET',
'callback' => array( $this, 'list_dosing' ),
'permission_callback' => '__return_true',
'args' => array(
'route' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'population' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
),
)
);
// POST /peptides/{id}/dosing (auth required).
register_rest_route(
self::REST_NAMESPACE,
'/peptides/(?P<id>\d+)/dosing',
array(
'methods' => 'POST',
'callback' => array( $this, 'create_dosing' ),
'permission_callback' => array( $this, 'check_write_permission' ),
)
);
// GET /peptides/{id}/legal.
register_rest_route(
self::REST_NAMESPACE,
'/peptides/(?P<id>\d+)/legal',
array(
'methods' => 'GET',
'callback' => array( $this, 'list_legal' ),
'permission_callback' => '__return_true',
)
);
// POST /peptides/{id}/legal (auth required).
register_rest_route(
self::REST_NAMESPACE,
'/peptides/(?P<id>\d+)/legal',
array(
'methods' => 'POST',
'callback' => array( $this, 'create_legal' ),
'permission_callback' => array( $this, 'check_write_permission' ),
)
);
}
/**
* List peptides with optional filters.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
public function list_peptides( \WP_REST_Request $request ): \WP_REST_Response {
$repo = new PR_Core_Peptide_Repository();
$search = $request->get_param( 'search' );
if ( $search ) {
$peptides = $repo->search( $search, (int) $request->get_param( 'per_page' ) );
} else {
$peptides = $repo->find_all(
array(
'category' => $request->get_param( 'category' ),
'evidence_strength' => $request->get_param( 'evidence_strength' ),
'per_page' => $request->get_param( 'per_page' ),
'page' => $request->get_param( 'page' ),
)
);
}
$data = array_map( static fn( PR_Core_Peptide_DTO $p ) => $p->to_array(), $peptides );
return new \WP_REST_Response( $data, 200 );
}
/**
* Get a single peptide by ID.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response|\WP_Error
*/
public function get_peptide( \WP_REST_Request $request ) {
$repo = new PR_Core_Peptide_Repository();
$peptide = $repo->find_by_id( (int) $request->get_param( 'id' ) );
if ( ! $peptide ) {
return new \WP_Error( 'not_found', __( 'Peptide not found.', 'peptide-repo-core' ), array( 'status' => 404 ) );
}
return new \WP_REST_Response( $peptide->to_array(), 200 );
}
/**
* List dosing rows for a peptide.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
public function list_dosing( \WP_REST_Request $request ): \WP_REST_Response {
$repo = new PR_Core_Dosing_Repository();
$rows = $repo->find_by_peptide(
(int) $request->get_param( 'id' ),
array_filter(
array(
'route' => $request->get_param( 'route' ),
'population' => $request->get_param( 'population' ),
)
)
);
$data = array_map( static fn( PR_Core_Dosing_Row_DTO $r ) => $r->to_array(), $rows );
return new \WP_REST_Response( $data, 200 );
}
/**
* Create a new dosing row for a peptide.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response|\WP_Error
*/
public function create_dosing( \WP_REST_Request $request ) {
$repo = new PR_Core_Dosing_Repository();
$data = $request->get_json_params();
$data['peptide_id'] = (int) $request->get_param( 'id' );
$data['added_by'] = get_current_user_id();
$id = $repo->insert( $data );
if ( 0 === $id ) {
return new \WP_Error( 'insert_failed', __( 'Failed to insert dosing row.', 'peptide-repo-core' ), array( 'status' => 500 ) );
}
$row = $repo->find_by_id( $id );
return new \WP_REST_Response( $row ? $row->to_array() : array( 'id' => $id ), 201 );
}
/**
* List legal cells for a peptide.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
public function list_legal( \WP_REST_Request $request ): \WP_REST_Response {
$repo = new PR_Core_Legal_Repository();
$cells = $repo->find_by_peptide( (int) $request->get_param( 'id' ) );
$data = array_map( static fn( PR_Core_Legal_Cell_DTO $c ) => $c->to_array(), $cells );
return new \WP_REST_Response( $data, 200 );
}
/**
* Create a new legal cell for a peptide.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response|\WP_Error
*/
public function create_legal( \WP_REST_Request $request ) {
$repo = new PR_Core_Legal_Repository();
$data = $request->get_json_params();
$data['peptide_id'] = (int) $request->get_param( 'id' );
$data['reviewer_id'] = get_current_user_id();
$id = $repo->insert( $data );
if ( 0 === $id ) {
return new \WP_Error( 'insert_failed', __( 'Failed to insert legal cell.', 'peptide-repo-core' ), array( 'status' => 500 ) );
}
$cell = $repo->find_by_id( $id );
return new \WP_REST_Response( $cell ? $cell->to_array() : array( 'id' => $id ), 201 );
}
/**
* Permission check: user must have manage_peptide_content capability.
*
* @return bool
*/
public function check_write_permission(): bool {
return current_user_can( PR_Core_Peptide_CPT::CAPABILITY );
}
}