<?php /* * Longitudinal Reports Plugin * Luke Stevens, Murdoch Childrens Research Institute https://www.mcri.edu.au * Version date 16-Nov-2015 */ require_once dirname(__FILE__) . '/config.php'; // Get html report table list($report_table, $num_results_returned) = LongitudinalReports::doReport($_POST['report_id'], 'report', 'html', false, false, false, false, false, false, false, false, false, false, false, isset($_GET['instruments']) ? explode(',', $_GET['instruments']) : array(), isset($_GET['events']) ? explode(',', $_GET['events']) : array()); // Display report and title and other text print "<div id='report_div' style='margin:10px 0 20px;'>" . RCView::div(array('style' => ''), RCView::div(array('class' => 'hide_in_print', 'style' => 'float:left;width:350px;'), RCView::div(array('style' => 'font-weight:bold;'), $lang['custom_reports_02'] . RCView::span(array('style' => 'margin-left:5px;color:#800000;font-size:15px;'), User::number_format_user($num_results_returned))) . RCView::div(array('style' => ''), $lang['custom_reports_03'] . RCView::span(array('style' => 'margin-left:5px;'), User::number_format_user(LongitudinalRecords::getRecordCount())) . (!$longitudinal ? "" : RCView::div(array('style' => 'margin-top:3px;color:#888;font-size:11px;font-family:tahoma,arial;'), $lang['custom_reports_09'])))) . RCView::div(array('class' => 'hide_in_print', 'style' => 'float:left;'), ($user_rights['data_export_tool'] == '0' ? '' : RCView::button(array('class' => 'report_btn jqbuttonmed', 'onclick' => "showExportFormatDialog('{$_POST['report_id']}');", 'style' => 'font-size:11px;padding:1px 4px 0px !important;'), RCView::img(array('src' => 'go-down.png', 'style' => 'vertical-align:middle;')) . RCView::span(array('style' => 'vertical-align:middle;'), $lang['custom_reports_12']))) . RCView::SP . RCView::button(array('class' => 'report_btn jqbuttonmed', 'onclick' => "window.print();", 'style' => 'font-size:11px;padding:1px 4px 0px !important;'), RCView::img(array('src' => 'printer.png', 'style' => 'vertical-align:middle;')) . RCView::span(array('style' => 'vertical-align:middle;'), $lang['custom_reports_13'])) . RCView::SP . ($_POST['report_id'] == 'ALL' || $_POST['report_id'] == 'SELECTED' || !$user_rights['reports'] ? '' : RCView::button(array('class' => 'report_btn jqbuttonmed', 'onclick' => "window.location.href = '" . APP_PATH_WEBROOT . LR_PATH_FROM_WEBROOT . "index.php?pid=" . PROJECT_ID . "&report_id={$_POST['report_id']}&addedit=1';", 'style' => 'font-size:11px;padding:1px 4px 0px !important;'), RCView::img(array('src' => 'pencil_small.png', 'style' => 'vertical-align:middle;')) . RCView::span(array('style' => 'vertical-align:middle;'), $lang['custom_reports_14'])))) . RCView::div(array('class' => 'clear'), '')) . RCView::div(array('id' => 'this_report_title', 'style' => 'margin:40px 0 8px;padding:5px 3px;color:#800000;font-size:18px;font-weight:bold;'), LongitudinalReports::getReportNames($_POST['report_id'])) . $report_table . "</div>";
public static function doReport($report_id = '0', $outputType = 'report', $outputFormat = 'html', $apiExportLabels = false, $apiExportHeadersAsLabels = false, $outputDags = false, $outputSurveyFields = false, $removeIdentifierFields = false, $hashRecordID = false, $removeUnvalidatedTextFields = false, $removeNotesFields = false, $removeDateFields = false, $dateShiftDates = false, $dateShiftSurveyTimestamps = false, $selectedInstruments = array(), $selectedEvents = array(), $returnIncludeRecordEventArray = false, $outputCheckboxLabel = false) { global $Proj, $user_rights, $isAjax, $app_title, $lang, $redcap_version; // Check report_id if (!is_numeric($report_id) && $report_id != 'ALL' && $report_id != 'SELECTED') { exit($isAjax ? '0' : 'ERROR'); } // Increase memory limit in case needed for intensive processing if (str_replace("M", "", ini_get('memory_limit')) < 1024) { ini_set('memory_limit', '1024M'); } // TESTING // if (isDev()) ini_set('memory_limit', '12M'); // Determine if this is API report export $isAPI = PAGE == 'api/index.php' || PAGE == 'API/index.php'; // Set flag to ALWAYS archive exported files in File Repository $archiveFiles = true; // Get report attributes $report = self::getReports($report_id, $selectedInstruments, $selectedEvents); if (empty($report)) { if ($isAPI) { exit(RestUtility::sendResponse(400, 'The value of the parameter "report_id" is not valid')); } else { exit($isAjax ? '0' : 'ERROR'); } } // Check user rights: Does user have access to this report? (exclude super users in this check) if (defined('SUPER_USER') && !SUPER_USER || !defined('SUPER_USER')) { // If user has Add/Edit Report rights then let them view this report, OR if they have explicit rights to this report if (self::getReportNames($report_id, !$user_rights['reports']) == null) { // User does NOT have access to this report AND also does not have Add/Edit Report rights if ($isAPI) { exit(RestUtility::sendResponse(403, "User \"" . USERID . "\" does not have access to this report.")); } else { exit($isAjax ? '0' : 'ERROR'); } } } // Determine if a report or an export $outputType = $outputType == 'report' ? 'report' : 'export'; if ($outputType != 'report') { $returnIncludeRecordEventArray = false; } // Determine whether to output a stats syntax file $stats_packages = array('r', 'spss', 'stata', 'sas'); // $outputSyntaxFile = (in_array($outputFormat, $stats_packages)); // If CSV, determine whether to output a stats syntax file $outputAsLabels = $outputFormat == 'csvlabels'; $outputHeadersAsLabels = $outputFormat == 'csvlabels'; // List of fields to export $fields = $report['fields']; // If removing any fields due to DE-IDENTIFICATION, loop through them and remove them if ($removeIdentifierFields || $removeUnvalidatedTextFields || $removeNotesFields || $removeDateFields) { foreach ($fields as $key => $this_event_field) { $this_field = self::getFieldFromEventField($this_event_field); // Skip record ID field if ($this_field == $Proj->table_pk) { continue; } // Get field type and validation type $this_field_type = $Proj->metadata[$this_field]['element_type']; $this_val_type = $Proj->metadata[$this_field]['element_validation_type']; $this_phi = $Proj->metadata[$this_field]['field_phi']; // Check if needs to be removed if ($this_phi && $removeIdentifierFields || $this_field_type == 'text' && $this_val_type == '' && $removeUnvalidatedTextFields || $this_field_type == 'textarea' && $removeNotesFields || $this_field_type == 'text' && $removeDateFields && substr($this_val_type, 0, 4) == 'date') { // Remove the field from $fields unset($fields[$key]); } } } // List of events to export $events = $report['limiter_events']; // Limit to user's DAG (if user is in a DAG), and if not in a DAG, then limit to the DAG filter $userInDAG = isset($user_rights['group_id']) && is_numeric($user_rights['group_id']); $dags = $userInDAG ? $user_rights['group_id'] : $report['filter_dags']; // Set options to include DAG names and/or survey fields (exclude ALL and SELECTED pre-defined reports) if (is_numeric($report_id)) { $outputDags = $report['output_dags'] == '1'; $outputSurveyFields = $report['output_survey_fields'] == '1'; } elseif (!is_numeric($report_id) && $outputType == 'report') { $outputDags = $outputSurveyFields = true; } // If user is in a DAG, then do not output the DAG name field if ($userInDAG) { $outputDags = false; } // If we're removing identifier fields, then also remove Survey Identifier (if outputting survey fields) $outputSurveyIdentifier = $outputSurveyFields && !$removeIdentifierFields; $outputScheduleDates = $report['output_schedule_dates']; $outputSurveyUrls = $report['output_survey_urls']; // File names for archived file $today_hm = date("Y-m-d_Hi"); $projTitleShort = substr(str_replace(" ", "", ucwords(preg_replace("/[^a-zA-Z0-9 ]/", "", html_entity_decode($app_title, ENT_QUOTES)))), 0, 20); if ($outputFormat == 'r' || $outputFormat == 'csvraw') { // CSV with header row $csv_filename = $projTitleShort . "_DATA_" . $today_hm . ".csv"; } elseif ($outputFormat == 'csvlabels') { // CSV labels $csv_filename = $projTitleShort . "_DATA_LABELS_" . $today_hm . ".csv"; } else { // CSV without header row $csv_filename = $projTitleShort . "_DATA_NOHDRS_" . $today_hm . ".csv"; } // Build sort array of sort fields and their attribute (ASC, DESC) $sortArray = array(); if ($report['orderby_field1'] != '') { $sortArray[$report['orderby_field1']] = $report['orderby_sort1']; } if ($report['orderby_field2'] != '') { $sortArray[$report['orderby_field2']] = $report['orderby_sort2']; } if ($report['orderby_field3'] != '') { $sortArray[$report['orderby_field3']] = $report['orderby_sort3']; } // If the only sort field is record ID field, then remove it (because it will sort by record ID and event on its own) if (count($sortArray) == 1 && isset($sortArray[$Proj->table_pk]) && $sortArray[$Proj->table_pk] == 'ASC') { unset($sortArray[$Proj->table_pk]); } ## BUILD AND STORE CSV FILE // Set output format (CSV or HTML or API format) if ($isAPI) { // For API report export, return in desired format $returnDataFormat = $outputFormat; $outputAsLabels = $apiExportLabels; $outputHeadersAsLabels = $apiExportHeadersAsLabels; } elseif ($outputType == 'report') { // For webpage report, return html $returnDataFormat = 'html'; } else { $returnDataFormat = 'csv'; } // Check syntax of logic string: If there is an issue in the logic, then return false and stop processing if ($outputType == 'report' && $report['limiter_logic'] != '' && !LogicTester::isValid($report['limiter_logic'])) { return array(RCView::div(array('class' => 'red'), RCView::img(array('src' => 'exclamation.png', 'class' => 'imgfix')) . RCView::b($lang['global_01'] . $lang['colon']) . " " . $lang['report_builder_132']), 0); } // Retrieve CSV data file $data_content = LongitudinalRecords::getData(PROJECT_ID, $returnDataFormat, array(), $fields, $events, $dags, false, $outputDags, $outputSurveyFields, $report['limiter_logic'], $outputAsLabels, $outputHeadersAsLabels, $hashRecordID, $dateShiftDates, $dateShiftSurveyTimestamps, $sortArray, $outputType != 'report', true, $returnIncludeRecordEventArray, true, $outputSurveyIdentifier, $outputCheckboxLabel, $outputScheduleDates, $outputSurveyUrls); // Replace any MS Word chacters in the data (from 6.12.0 string passed by ref) if (version_compare($redcap_version, '6.12.0', '<')) { $data_content = replaceMSchars($data_content); } else { //replaceMSchars(is_array($data_content) ? $data_content[0] : $data_content); //"Only variables can be passed by reference" if (is_array($data_content)) { replaceMSchars($data_content[0]); } else { replaceMSchars($data_content); } } ## Logging (for exports only) if ($outputType != 'report' || $isAPI) { // Set data_values as JSON-encoded $data_values = array('report_id' => $report_id, 'export_format' => substr($outputFormat, 0, 3) == 'csv' ? 'CSV' : strtoupper($outputFormat), 'rawOrLabel' => $outputAsLabels ? 'label' : 'raw'); if ($outputDags) { $data_values['export_data_access_group'] = 'Yes'; } if ($outputSurveyFields) { $data_values['export_survey_fields'] = 'Yes'; } if ($dateShiftDates) { $data_values['date_shifted'] = 'Yes'; } if (isset($user_rights['data_export_tool']) && $user_rights['data_export_tool'] == '2') { $data_values['deidentified'] = 'Yes'; } if (isset($user_rights['data_export_tool']) && $user_rights['data_export_tool'] == '3') { $data_values['removed_identifiers'] = 'Yes'; } $data_values['fields'] = empty($fields) ? array_keys($Proj->metadata) : $fields; // Log it log_event("", "redcap_data", "longitudinal_report", "", json_encode($data_values), "Longitudinal Report" . ($isAPI ? " (API)" : "")); } // IF OUTPUTTING A REPORT, RETURN THE CONTENT HERE if ($outputType == 'report' || $isAPI) { return $data_content; } // For SAS, SPSS, and Stata, remove the CSV file's header row if (in_array($outputFormat, array('spss', 'stata', 'sas'))) { // Remove header row list($headers, $data_content) = explode("\n", $data_content, 2); } // Store the data file $data_edoc_id = self::storeExportFile($csv_filename, $data_content, $archiveFiles, $dateShiftDates); if ($data_edoc_id === false) { return false; } /* Stats syntax not implemented for Longitudinal Reports ## BUILD AND STORE SYNTAX FILE (if applicable) // If exporting to a stats package, then also generate the associate syntax file for that package $syntax_edoc_id = null; if ($outputSyntaxFile) { // Generate syntax file $syntax_file_contents = self::getStatsPackageSyntax($outputFormat, $fields, $csv_filename, $outputDags, $outputSurveyFields, $removeIdentifierFields); // Set the filename of the syntax file if ($outputFormat == 'spss') { $stats_package_filename = $projTitleShort ."_" . strtoupper($outputFormat) . "_$today_hm.sps"; } elseif ($outputFormat == 'stata') { $stats_package_filename = $projTitleShort ."_" . strtoupper($outputFormat) . "_$today_hm.do"; } else { $stats_package_filename = $projTitleShort ."_" . strtoupper($outputFormat) . "_$today_hm.$outputFormat"; } // Store the syntax file $syntax_edoc_id = self::storeExportFile($stats_package_filename, $syntax_file_contents, $archiveFiles, $dateShiftDates); if ($syntax_edoc_id === false) return false; } */ $syntax_edoc_id = null; // Return the edoc_id's of the CSV data file return array($data_edoc_id, $syntax_edoc_id); }