Adopt reusable CI standard + PHPUnit conversion (#22)
Squash-merge of PR #22: adopt shared reusable CI workflow, convert PHPUnit to stubs, update branch-protection contexts.
QA-approved at 05d8094a1d. All required CI checks green.
Agent-Session: 2026-06-17-prcore-ci-deploy
This commit is contained in:
@@ -1,6 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* Candidate Queue Repository.
|
||||
*
|
||||
* @package Peptide_Repo_Core
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CRUD for AI-extracted dosing candidates awaiting human review
|
||||
*
|
||||
* @package Peptide_Repo_Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* Repository for AI candidate queue (pr_ai_candidate_queue table).
|
||||
*
|
||||
@@ -28,7 +40,7 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
$row = $wpdb->get_row(
|
||||
$wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $id ),
|
||||
$wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", $id ), // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
@@ -47,25 +59,25 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
global $wpdb;
|
||||
$table = $wpdb->prefix . 'pr_ai_candidate_queue';
|
||||
|
||||
$where = [ 'queue_status = %s' ];
|
||||
$params = [ sanitize_text_field( $status ) ];
|
||||
$where = array( 'queue_status = %s' );
|
||||
$params = array( sanitize_text_field( $status ) );
|
||||
|
||||
if ( $peptide_id > 0 ) {
|
||||
$where[] = 'peptide_id = %d';
|
||||
$params[] = $peptide_id;
|
||||
}
|
||||
|
||||
$params[] = $limit;
|
||||
$params[] = $limit;
|
||||
$where_sql = implode( ' AND ', $where );
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
$rows = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT * FROM {$table} WHERE {$where_sql} ORDER BY extraction_confidence DESC LIMIT %d",
|
||||
"SELECT * FROM {$table} WHERE {$where_sql} ORDER BY extraction_confidence DESC LIMIT %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
...$params
|
||||
),
|
||||
ARRAY_A
|
||||
) ?: [];
|
||||
) ?: array(); // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
|
||||
|
||||
return array_map(
|
||||
static fn( array $row ) => new PR_Core_Candidate_DTO( $row ),
|
||||
@@ -85,7 +97,7 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
global $wpdb;
|
||||
$table = $wpdb->prefix . 'pr_ai_candidate_queue';
|
||||
|
||||
$row = [
|
||||
$row = array(
|
||||
'peptide_id' => absint( $data['peptide_id'] ?? 0 ),
|
||||
'dose_min' => isset( $data['dose_min'] ) ? (float) $data['dose_min'] : null,
|
||||
'dose_max' => isset( $data['dose_max'] ) ? (float) $data['dose_max'] : null,
|
||||
@@ -106,7 +118,7 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
'extraction_confidence' => (float) ( $data['extraction_confidence'] ?? 0 ),
|
||||
'queue_status' => 'pending',
|
||||
'extracted_at' => current_time( 'mysql' ),
|
||||
];
|
||||
);
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
$result = $wpdb->insert( $table, $row );
|
||||
@@ -134,30 +146,32 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
|
||||
// Copy candidate data into a dosing row.
|
||||
$dosing_repo = new PR_Core_Dosing_Repository();
|
||||
$dosing_id = $dosing_repo->insert( [
|
||||
'peptide_id' => $candidate->peptide_id,
|
||||
'dose_min' => $candidate->dose_min,
|
||||
'dose_max' => $candidate->dose_max,
|
||||
'dose_unit' => $candidate->dose_unit,
|
||||
'route' => $candidate->route,
|
||||
'frequency' => $candidate->frequency,
|
||||
'duration_value' => $candidate->duration_value,
|
||||
'duration_unit' => $candidate->duration_unit,
|
||||
'population' => $candidate->population,
|
||||
'indication' => $candidate->indication,
|
||||
'evidence_strength' => $candidate->evidence_strength,
|
||||
'study_title' => $candidate->study_title,
|
||||
'study_year' => $candidate->study_year,
|
||||
'citation_pubmed_id' => $candidate->citation_pubmed_id,
|
||||
'citation_doi' => $candidate->citation_doi,
|
||||
'citation_url' => $candidate->citation_url,
|
||||
'notes' => $candidate->notes,
|
||||
'source' => 'ai-candidate-approved',
|
||||
'ai_candidate_id' => $candidate_id,
|
||||
'added_by' => $reviewer_id,
|
||||
'reviewed_by' => $reviewer_id,
|
||||
'reviewed_at' => current_time( 'mysql' ),
|
||||
] );
|
||||
$dosing_id = $dosing_repo->insert(
|
||||
array(
|
||||
'peptide_id' => $candidate->peptide_id,
|
||||
'dose_min' => $candidate->dose_min,
|
||||
'dose_max' => $candidate->dose_max,
|
||||
'dose_unit' => $candidate->dose_unit,
|
||||
'route' => $candidate->route,
|
||||
'frequency' => $candidate->frequency,
|
||||
'duration_value' => $candidate->duration_value,
|
||||
'duration_unit' => $candidate->duration_unit,
|
||||
'population' => $candidate->population,
|
||||
'indication' => $candidate->indication,
|
||||
'evidence_strength' => $candidate->evidence_strength,
|
||||
'study_title' => $candidate->study_title,
|
||||
'study_year' => $candidate->study_year,
|
||||
'citation_pubmed_id' => $candidate->citation_pubmed_id,
|
||||
'citation_doi' => $candidate->citation_doi,
|
||||
'citation_url' => $candidate->citation_url,
|
||||
'notes' => $candidate->notes,
|
||||
'source' => 'ai-candidate-approved',
|
||||
'ai_candidate_id' => $candidate_id,
|
||||
'added_by' => $reviewer_id,
|
||||
'reviewed_by' => $reviewer_id,
|
||||
'reviewed_at' => current_time( 'mysql' ),
|
||||
)
|
||||
);
|
||||
|
||||
if ( 0 === $dosing_id ) {
|
||||
return 0;
|
||||
@@ -204,7 +218,7 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
return (int) $wpdb->get_var(
|
||||
$wpdb->prepare( "SELECT COUNT(*) FROM {$table} WHERE queue_status = %s", $status )
|
||||
$wpdb->prepare( "SELECT COUNT(*) FROM {$table} WHERE queue_status = %s", $status ) // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,15 +238,15 @@ class PR_Core_Candidate_Queue_Repository {
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
$result = $wpdb->update(
|
||||
$table,
|
||||
[
|
||||
array(
|
||||
'queue_status' => sanitize_text_field( $status ),
|
||||
'reviewed_by' => $reviewer_id,
|
||||
'reviewed_at' => current_time( 'mysql' ),
|
||||
'reviewer_notes' => sanitize_textarea_field( $notes ),
|
||||
],
|
||||
[ 'id' => $id ],
|
||||
[ '%s', '%d', '%s', '%s' ],
|
||||
[ '%d' ]
|
||||
),
|
||||
array( 'id' => $id ),
|
||||
array( '%s', '%d', '%s', '%s' ),
|
||||
array( '%d' )
|
||||
);
|
||||
|
||||
return false !== $result;
|
||||
|
||||
Reference in New Issue
Block a user