Skip to content

Commit e689e47

Browse files
committed
add randomization test
1 parent 029f612 commit e689e47

File tree

8 files changed

+187
-20
lines changed

8 files changed

+187
-20
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
A test for this API was written in testrandomization.php.
66

7-
The test can be executed by calling url https://localhost/api/?type=module&prefix=Randapi&page=testrandomization&pid=20&NOAUTH
7+
The test can be executed by calling url https://localhost/api/?type=module&prefix=Randapi&page=testrandomization&pid=20&NOAUTH&token=F33F6876ADC5EC63CE79EBFF88FF0092
88

99
It requires:
1010

1111
* The RandomizationTest project to be loaded. cfr. resources/RandomizationTest_dist.csv for the project dictionary or RandomizationTest.xml for the full project metadata xml.
1212
* A user with an access token who is assigned to the Project Admin role. This user must be able to perform randomization and to add records.
13-
* The Allocation table to be loaded. Cfr. [resources/RandomizationAllocation.csv](https://github.com/redcapuzgent/randapi/blob/master/resources/RandomizationAllocation.csv)
13+
* The Allocation table should be loaded. Cfr. [resources/RandomizationAllocation.csv](https://github.com/redcapuzgent/randapi/blob/master/resources/RandomizationAllocation.csv)
1414

1515
There are 3 groups (A,B and C). They are saved in `randgroup`.
1616
Randomization must occur within these groups for 2 possible outcomes (X and Y). The result is saved in `assignedto`.

Randapi.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ function randomizeRecord($recordId,$projectId,$fields=array(),$resultFieldName,$
2828
global $redcap_version;
2929
$classesPath = __DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR."redcap_v$redcap_version".DIRECTORY_SEPARATOR."Classes".DIRECTORY_SEPARATOR;
3030
require_once($classesPath."Randomization.php");
31-
require_once(__DIR__ . DIRECTORY_SEPARATOR);
31+
require_once(__DIR__ . DIRECTORY_SEPARATOR."/model/RandomizationField.php");
3232

3333
if(!defined(PROJECT_ID)){
34-
error_log("defining project id");
35-
define(PROJECT_ID,$this->getProjectId());
34+
error_log("defining project id $projectId");
35+
define(PROJECT_ID,$projectId);
3636
}else{
3737
error_log("project id was already defined");
3838
}
3939
global $longitudinal;
4040
if(!isset($longitudinal)){
4141
error_log("defining longitudinal");
42-
$proj = new Project($projectId, true);
42+
//echo "requiring $classesPath"."Project.php";
43+
require_once($classesPath."Project.php");
44+
$proj = new \Project($projectId, true);
4345
$longitudinal = $proj->longitudinal;
4446
}else{
4547
error_log("longitudinal was already defined");

api.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// https://localhost/api/?type=module&prefix=Randapi&page=api&NOAUTH
55
require_once 'model/RandapiException.php';
66
require_once 'model/RandomizationAllocation.php';
7+
require_once 'model/RandomizationField.php';
78

89
/**
910
* @param $jsonObject
@@ -46,6 +47,55 @@ function handleAddAllocation(\redcapuzgent\Randapi\Randapi $randapi, $jsonObject
4647
$allocations);
4748
}
4849

50+
/**
51+
* @param \redcapuzgent\Randapi\Randapi $randapi
52+
* @param $jsonObject
53+
* @return string
54+
* @throws RandapiException
55+
*/
56+
function handleRandomization(\redcapuzgent\Randapi\Randapi $randapi, $jsonObject){
57+
if(!property_exists($jsonObject,"parameters")){
58+
throw new RandapiException("parameters property not found.");
59+
}
60+
if(!property_exists($jsonObject->parameters, "recordId")){
61+
throw new RandapiException("parameters->recordId property not found.");
62+
}
63+
if(!property_exists($jsonObject->parameters, "projectId")){
64+
throw new RandapiException("parameters->projectId property not found.");
65+
}
66+
if(!property_exists($jsonObject->parameters, "fields")){
67+
throw new RandapiException("parameters->fields property not found.");
68+
}
69+
if(!property_exists($jsonObject->parameters, "resultFieldName")){
70+
throw new RandapiException("parameters->resultFieldName property not found.");
71+
}
72+
73+
// optional
74+
$groupId = "";
75+
if(property_exists($jsonObject->parameters, "groupId")){
76+
$groupId = $jsonObject->parameters->groupId;
77+
}
78+
$armName = "Arm 1";
79+
if(property_exists($jsonObject->parameters, "armName")){
80+
$groupId = $jsonObject->parameters->armName;
81+
}
82+
$eventName = "Event 1";
83+
if(property_exists($jsonObject->parameters, "eventName")){
84+
$eventName = $jsonObject->parameters->eventName;
85+
}
86+
87+
$fields = array();
88+
foreach($jsonObject->parameters->fields as $field){
89+
array_push($fields,\redcapuzgent\Randapi\RandomizationField::fromStdClass($field));
90+
}
91+
//randomizeRecord($recordId,$projectId,$fields=array(),$resultFieldName,$group_id='',$arm_name='Arm 1', $event_name='Event 1'){
92+
return $randapi->randomizeRecord($jsonObject->parameters->recordId,
93+
$jsonObject->parameters->projectId,
94+
$fields,
95+
$jsonObject->parameters->resultFieldName,
96+
$groupId,$armName,$eventName);
97+
}
98+
4999
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
50100

51101
header('Content-Type: application/json');
@@ -59,6 +109,13 @@ function handleAddAllocation(\redcapuzgent\Randapi\Randapi $randapi, $jsonObject
59109
case "addRecordsToAllocationTable":
60110
handleAddAllocation($module,$jsonObject);
61111
break;
112+
case "randomizeRecord":
113+
handleRandomization($module,$jsonObject);
114+
break;
115+
default:
116+
http_response_code(500);
117+
echo json_encode("incorrect action");
118+
exit(0);
62119
}
63120
echo json_encode("success");
64121
}catch(RandapiException $e){

model/RandapiException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public function jsonSerialize()
1212
return [
1313
"message"=>$this->message,
1414
"code"=>$this->code,
15-
"previous"=>!is_null($this->getPrevious())?$this->getPrevious()->getTraceAsString():null
15+
"previous"=>!is_null($this->getPrevious())?$this->getPrevious()->getMessage()." ".$this->getPrevious()->getTraceAsString():null
1616
];
1717
}
1818
}

model/RandomizationField.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace redcapuzgent\Randapi;
44

5-
class RandomizationField
5+
class RandomizationField implements \JsonSerializable
66
{
77
/**
88
* @var string
@@ -40,4 +40,21 @@ public function getValue(): string
4040
return $this->value;
4141
}
4242

43+
public static function fromStdClass(\stdClass $in){
44+
if(property_exists($in,"key") &&
45+
property_exists($in,"value")){
46+
return new RandomizationField($in->key, $in->value);
47+
}else{
48+
throw new \RandapiException("Could not create RandomizationField. Object does not have properties key and value");
49+
}
50+
}
51+
52+
public function jsonSerialize()
53+
{
54+
return [
55+
"key"=>$this->getKey(),
56+
"value"=>$this->getValue()
57+
];
58+
}
59+
4360
}

testrandomization.php

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
require_once(__DIR__.DIRECTORY_SEPARATOR."vendor/autoload.php");
4-
require_once(__DIR__ . DIRECTORY_SEPARATOR);
4+
require_once(__DIR__.DIRECTORY_SEPARATOR . "model/RandomizationField.php");
55

66
use IU\PHPCap\RedCapProject;
77
use redcapuzgent\Randapi\RandomizationField;
@@ -11,14 +11,14 @@
1111

1212
$token = $_GET["token"];
1313
/* @var $module \redcapuzgent\Randapi\Randapi*/
14-
$apiUrl = "https://".$_SERVER['HTTP_HOST']."/api/"; //$module->getUrl("",true, true);
14+
$apiUrl = APP_PATH_WEBROOT_FULL."api/";
1515

16-
error_log("retrieved token $token and url $apiUrl");
16+
error_log("retrieved token $token and url $apiUrl and projectId ".$module->getProjectId());
1717

1818
$project = new RedCapProject($apiUrl,$token);
19-
$existingRecords = $module->getData(array(
20-
'return_format'=>'php',
21-
'fields'=>array("record_id")
19+
$existingRecords = REDCap::getData(array(
20+
'return_format'=>'array',
21+
'fields'=>"record_id"
2222
));
2323

2424
//$existingRecords = $project->exportRecords('php','flat',null,array("record_id"));
@@ -27,9 +27,9 @@
2727

2828
if (sizeof($existingRecords) > 0) {
2929
$recordsToDelete = array();
30-
foreach ($existingRecords as $record) {
31-
error_log("removing record: " . $record["record_id"]);
32-
$recordsToDelete[sizeof($recordsToDelete)] = $record["record_id"];
30+
foreach ($existingRecords as $recordId => $record) {
31+
error_log("removing record: " . $recordId);
32+
$recordsToDelete[sizeof($recordsToDelete)] = $recordId;
3333
}
3434
error_log("deleting records with ids: " .print_r($recordsToDelete,true));
3535
$deleteResult = $project->deleteRecords($recordsToDelete);
@@ -59,7 +59,7 @@
5959

6060
$importResponse = $project->importRecords($testSet);
6161

62-
if ($importResponse->count != 3) {
62+
if ($importResponse != 3) {
6363
error_log("response after importing: " . print_r($importResponse, true));
6464
error_log("Could not import records!!!");
6565
} else {
@@ -74,8 +74,41 @@
7474
foreach ($testSet as $test) {
7575
$fields = array(new RandomizationField("randgroup", $test->randgroup));
7676
try {
77-
$assignedAid = $module->randomizeRecord($test->record_id, $project_id, $fields,"assignedto");
78-
error_log("assigned for records $test->record_id aid: $assignedAid");
77+
78+
$url = APP_PATH_WEBROOT_FULL."api/?type=module&prefix=Randapi&page=api&NOAUTH";
79+
$postfields = [
80+
"action"=>"randomizeRecord",
81+
"parameters"=> [
82+
"recordId" => $test->record_id,
83+
"projectId" => $module->getProjectId(),
84+
"fields" => $fields,
85+
"resultFieldName"=>"assignedto"
86+
]
87+
];
88+
89+
$ch = curl_init();
90+
curl_setopt($ch, CURLOPT_URL, $url);
91+
curl_setopt($ch, CURLOPT_POST, 1);
92+
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postfields));
93+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
94+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Set to TRUE for production use
95+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Set to TRUE for production use
96+
curl_setopt($ch, CURLOPT_VERBOSE, 0);
97+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
98+
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
99+
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
100+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
101+
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
102+
103+
$output = curl_exec($ch);
104+
if(!$output){
105+
echo 'Curl error: ' . curl_error($ch)."\n";
106+
}else{
107+
}
108+
curl_close($ch);
109+
$assignedAid = json_decode($output);
110+
111+
error_log("assigned for records $test->record_id aid: $output");
79112
$assignedAids[$test->record_id - 1] = $assignedAid;
80113
} catch (Exception $e) {
81114
error_log("error while randomizing: " . $e->getMessage() . " " . $e->getTraceAsString());

typescript/RandomizeRecordAction.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {RandApiAction} from "./RandApiAction";
2+
import {RandomizeRecordParameters} from "./RandomizeRecordParameters";
3+
4+
export class RandomizeRecordAction extends RandApiAction{
5+
public parameters: RandomizeRecordParameters;
6+
7+
constructor(parameters:RandomizeRecordParameters){
8+
super("randomizeRecord", parameters);
9+
}
10+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {RandomizationField} from "./RandomizationField";
2+
3+
export class RandomizeRecordParameters{
4+
5+
/**
6+
*
7+
* @param recordId The record that we want to randomize
8+
* @param projectId The projectId where the record belongs to
9+
* @param fields An array of RandomizationFields
10+
* @param resultFieldName The field where the randomization result can be stored.
11+
* @param groupId (optional) The DAG identifier. default = '' (none)
12+
* @param armName (optional) The name of the arm. default = 'Arm 1'
13+
* @param eventName (optional) The name of the event. default = 'Event 1'
14+
*/
15+
constructor(private recordId: string, private projectId: string, private fields: RandomizationField[],
16+
private resultFieldName: string, private groupId: string = '',
17+
private armName: string= 'Arm 1', private eventName: string = 'Event 1') {
18+
}
19+
20+
21+
getRecordId(): string {
22+
return this.recordId;
23+
}
24+
25+
getProjectId(): string {
26+
return this.projectId;
27+
}
28+
29+
getFields(): RandomizationField[] {
30+
return this.fields;
31+
}
32+
33+
getResultFieldName(): string {
34+
return this.resultFieldName;
35+
}
36+
37+
getGroupId(): string {
38+
return this.groupId;
39+
}
40+
41+
getArmName(): string {
42+
return this.armName;
43+
}
44+
45+
getEventName(): string {
46+
return this.eventName;
47+
}
48+
}

0 commit comments

Comments
 (0)