File Manager
Upload
Current Directory: /home/lartcid/public_html/journal.lartc.id
[Back]
..
[Open]
Hapus
Rename
.htaccess
[Edit]
Hapus
Rename
.well-known
[Open]
Hapus
Rename
README.md
[Edit]
Hapus
Rename
api
[Open]
Hapus
Rename
cache
[Open]
Hapus
Rename
cgi-bin
[Open]
Hapus
Rename
classes
[Open]
Hapus
Rename
config.TEMPLATE.inc.php
[Edit]
Hapus
Rename
config.inc.php
[Edit]
Hapus
Rename
controllers
[Open]
Hapus
Rename
cypress.json
[Edit]
Hapus
Rename
dbscripts
[Open]
Hapus
Rename
docs
[Open]
Hapus
Rename
error_log
[Edit]
Hapus
Rename
favicon.ico
[Edit]
Hapus
Rename
index.php
[Edit]
Hapus
Rename
js
[Open]
Hapus
Rename
lib
[Open]
Hapus
Rename
locale
[Open]
Hapus
Rename
mini.php
[Edit]
Hapus
Rename
pages
[Open]
Hapus
Rename
php.ini
[Edit]
Hapus
Rename
plugins
[Open]
Hapus
Rename
public
[Open]
Hapus
Rename
registry
[Open]
Hapus
Rename
scheduledTaskLogs
[Open]
Hapus
Rename
schemas
[Open]
Hapus
Rename
styles
[Open]
Hapus
Rename
templates
[Open]
Hapus
Rename
tools
[Open]
Hapus
Rename
Edit File
<?php /** * @defgroup lib_pkp_classes_statistics */ /** * @file lib/pkp/classes/statistics/PKPMetricsDAO.inc.php * * Copyright (c) 2014-2021 Simon Fraser University * Copyright (c) 2003-2021 John Willinsky * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. * * @class PKPMetricsDAO * @ingroup lib_pkp_classes_statistics * * @brief Class with basic operations for retrieving and adding statistics data. */ import('classes.statistics.StatisticsHelper'); //STATISTICS_DIMENSION_ class PKPMetricsDAO extends DAO { /** * Retrieve a range of aggregate, filtered, ordered metric values, i.e. * a statistics report. * * @see <https://pkp.sfu.ca/wiki/index.php/OJSdeStatisticsConcept#Input_and_Output_Formats_.28Aggregation.2C_Filters.2C_Metrics_Data.29> * for a full specification of the input and output format of this method. * * @param $metricType string|array metrics selection * @param $columns string|array column (aggregation level) selection * @param $filters array report-level filter selection * @param $orderBy array order criteria * @param $range null|DBResultRange paging specification * @param $nonAdditive boolean (optional) Whether the metric type dimension * will be additive or not. This must be used with care, different metric types * should not be additive because they may diverge in ways of counting usage events. * * @return null|array The selected data as a simple tabular result set or * null if metrics are not supported, the specified report * is invalid or cannot be produced or another error occurred. */ function &getMetrics($metricType, $columns = array(), $filters = array(), $orderBy = array(), $range = null, $nonAdditive = true) { // Return by reference. $nullVar = null; // Canonicalize and validate parameter format. if (is_scalar($metricType)) $metricType = array($metricType); if (is_scalar($columns)) $columns = array($columns); if (!(is_array($filters) && is_array($orderBy))) return $nullVar; // Validate parameter content. foreach ($metricType as $metricTypeElement) { if (!is_string($metricTypeElement)) return $nullVar; } $validColumns = array( STATISTICS_DIMENSION_CONTEXT_ID, STATISTICS_DIMENSION_PKP_SECTION_ID, STATISTICS_DIMENSION_ASSOC_OBJECT_ID, STATISTICS_DIMENSION_ASSOC_OBJECT_TYPE, STATISTICS_DIMENSION_SUBMISSION_ID, STATISTICS_DIMENSION_REPRESENTATION_ID, STATISTICS_DIMENSION_FILE_TYPE, STATISTICS_DIMENSION_ASSOC_TYPE, STATISTICS_DIMENSION_ASSOC_ID, STATISTICS_DIMENSION_COUNTRY, STATISTICS_DIMENSION_REGION, STATISTICS_DIMENSION_CITY, STATISTICS_DIMENSION_MONTH, STATISTICS_DIMENSION_DAY, STATISTICS_DIMENSION_METRIC_TYPE ); // If the metric column was defined, remove it. We've already // add that below. $metricKey = array_search(STATISTICS_METRIC, $columns); if ($metricKey !== false) unset($columns[$metricKey]); if (count(array_diff($columns, $validColumns)) > 0) return $nullVar; $validColumns[] = STATISTICS_METRIC; foreach ($filters as $filterColumn => $value) { if (!in_array($filterColumn, $validColumns)) return $nullVar; } $validDirections = array(STATISTICS_ORDER_ASC, STATISTICS_ORDER_DESC); foreach ($orderBy as $orderColumn => $direction) { if (!in_array($orderColumn, $validColumns)) return $nullVar; if (!in_array($direction, $validDirections)) return $nullVar; } // Validate correct use of the (non-additive) metric type dimension. We // either require a filter on a single metric type or the metric type // must be present as a column. if (empty($metricType)) return $nullVar; if (count($metricType) !== 1 && $nonAdditive) { if (!in_array(STATISTICS_DIMENSION_METRIC_TYPE, $columns)) { array_push($columns, STATISTICS_DIMENSION_METRIC_TYPE); } } // Add the metric type as filter. $filters[STATISTICS_DIMENSION_METRIC_TYPE] = $metricType; // Build the select and group by clauses. if (empty($columns)) { $selectClause = 'SELECT SUM(metric) AS metric'; $groupByClause = ''; } else { $selectedColumns = implode(', ', $columns); $selectClause = "SELECT $selectedColumns, SUM(metric) AS metric"; $groupByClause = "GROUP BY $selectedColumns"; } // Build the where and having clauses. $params = array(); $whereClause = ''; $havingClause = ''; $isFirst = true; foreach ($filters as $column => $values) { // The filter array contains STATISTICS_* constants for the filtered // hierarchy aggregation level as keys. if ($column === STATISTICS_METRIC) { $havingClause = 'HAVING '; $currentClause =& $havingClause; // Reference required. } else { if ($isFirst && $column) { $whereClause = 'WHERE '; $isFirst = false; } else { $whereClause .= ' AND '; } $currentClause =& $whereClause; // Reference required. } if (is_object($values)) { $values = (array) $values; } if (is_array($values) && isset($values['from'])) { // Range filter: The value is a hashed array with from/to entries. if (!isset($values['to'])) return $nullVar; $currentClause .= "($column BETWEEN ? AND ?)"; $params[] = $values['from']; $params[] = $values['to']; } else { // Element selection filter: The value is a scalar or an // unordered array of one or more hierarchy element IDs. if (is_array($values) && count($values) === 1) { $values = array_pop($values); } if (is_scalar($values)) { $currentClause .= "$column = ?"; $params[] = $values; } elseif (count($values)) { $placeholders = array_pad(array(), count($values), '?'); $placeholders = implode(', ', $placeholders); $currentClause .= "$column IN ($placeholders)"; foreach ($values as $value) { $params[] = $value; } } else { // count($values) == 0: No matches should be returned. $currentClause .= '1=0'; } } unset($currentClause); } // Replace the current time constant by time values // inside the parameters array. $currentTime = array( STATISTICS_YESTERDAY => date('Ymd', strtotime('-1 day', time())), STATISTICS_CURRENT_MONTH => date('Ym', time())); foreach ($currentTime as $constant => $time) { $currentTimeKeys = array_keys($params, $constant); foreach ($currentTimeKeys as $key) { $params[$key] = $time; } } // Build the order-by clause. $orderByClause = ''; if (count($orderBy) > 0) { $isFirst = true; foreach ($orderBy as $orderColumn => $direction) { if ($isFirst) { $orderByClause = 'ORDER BY '; } else { $orderByClause .= ', '; } $orderByClause .= "$orderColumn $direction"; $isFirst = false; } } // Build the report. $sql = "$selectClause FROM metrics $whereClause $groupByClause $havingClause $orderByClause"; if (is_a($range, 'DBResultRange')) $result = $this->retrieveRange($sql, $params, $range); else $result = $this->retrieve($sql, $params); // Return the report. $returner = []; foreach ($result as $row) { $returner[] = (array) $row; } return $returner; } /** * Get all load ids that are associated * with records filtered by the passed * arguments. * @param $assocType int * @param $assocId int * @param $metricType string * @return array */ function getLoadId($assocType, $assocId, $metricType) { $result = $this->retrieve('SELECT load_id FROM metrics WHERE assoc_type = ? AND assoc_id = ? AND metric_type = ? GROUP BY load_id', [$assocType, $assocId, $metricType]); $loadIds = []; foreach ($result as $row) { $loadIds[] = $row->load_id; } return $loadIds; } /** * Check for the presence of any record * that has the passed metric type. * @param $metricType string * @return boolean */ function hasRecord($metricType) { $result = $this->retrieve('SELECT load_id FROM metrics WHERE metric_type = ? LIMIT 1', [$metricType]); return (boolean) $result->current(); } /** * Purge a load batch. * * @param $loadId string */ function purgeLoadBatch($loadId) { $this->update('DELETE FROM metrics WHERE load_id = ?', [$loadId]); // Not a number. } /** * Purge all records associated with the passed metric type * until the passed date. * @param $metricType string * @param $toDate string */ function purgeRecords($metricType, $toDate) { $this->update('DELETE FROM metrics WHERE metric_type = ? AND day IS NOT NULL AND day <= ?', [$metricType, $toDate]); } /** * Insert an entry into metrics table. * * @param $record array * @param $errorMsg string */ function insertRecord($record) { $recordToStore = array(); // Required dimensions. $requiredDimensions = ['load_id', 'assoc_type', 'assoc_id', 'metric_type']; foreach ($requiredDimensions as $requiredDimension) { if (!isset($record[$requiredDimension])) { throw new Exception('Cannot load record: missing dimension "' . $requiredDimension . '".'); } $recordToStore[$requiredDimension] = $record[$requiredDimension]; } $assocType = $recordToStore['assoc_type'] = (int)$recordToStore['assoc_type']; $assocId = $recordToStore['assoc_id'] = (int)$recordToStore['assoc_id']; list($contextId, $pkpSectionId, $assocObjType, $assocObjId, $submissionId, $representationId) = $this->foreignKeyLookup($assocType, $assocId); $recordToStore['context_id'] = $contextId; $recordToStore['pkp_section_id'] = $pkpSectionId; $recordToStore['assoc_object_type'] = $assocObjType; $recordToStore['assoc_object_id'] = $assocObjId; $recordToStore['submission_id'] = $submissionId; $recordToStore['representation_id'] = $representationId; // File type is optional. if (isset($record['file_type']) && $record['file_type']) $recordToStore['file_type'] = (int)$record['file_type']; // We require either month or day in the time dimension. if (isset($record['day'])) { if (!PKPString::regexp_match('/[0-9]{8}/', $record['day'])) { throw new Exception('Cannot load record: invalid date.'); } $recordToStore['day'] = $record['day']; $recordToStore['month'] = substr($record['day'], 0, 6); if (isset($record['month']) && $recordToStore['month'] != $record['month']) { throw new Exception('Cannot load record: invalid month.'); } } elseif (isset($record['month'])) { if (!PKPString::regexp_match('/[0-9]{6}/', $record['month'])) { throw new Exception('Cannot load record: invalid month.'); } $recordToStore['month'] = $record['month']; } else { throw new Exception('Cannot load record: Missing time dimension.'); } // Geolocation is optional. if (isset($record['country_id'])) $recordToStore['country_id'] = (string)$record['country_id']; if (isset($record['region'])) $recordToStore['region'] = (string)$record['region']; if (isset($record['city'])) $recordToStore['city'] = (string)$record['city']; // The metric must be set. If it is 0 we ignore the record. if (!isset($record['metric'])) { throw new Exception('Cannot load record: metric is missing.'); } if (!is_numeric($record['metric'])) { throw new Exception('Cannot load record: invalid metric.'); } $recordToStore['metric'] = (int) $record['metric']; // Save the record to the database. $fields = implode(', ', array_keys($recordToStore)); $placeholders = implode(', ', array_pad(array(), count($recordToStore), '?')); $params = array_values($recordToStore); return $this->update("INSERT INTO metrics ($fields) VALUES ($placeholders)", $params); } // // Protected methods. // /** * Foreign key lookup for the published object dimension. * @param $assocType int * @param $assocId int * @return array Values must be foreign keys relative to the * context, pkp section, associated object (type and id), submission * and representation. */ protected function foreignKeyLookup($assocType, $assocId) { $contextId = $sectionId = $submissionId = $assocObjectType = $assocObjectId = $representationId = null; $isFile = false; $isRepresentation = false; switch($assocType) { case ASSOC_TYPE_SUBMISSION_FILE: case ASSOC_TYPE_SUBMISSION_FILE_COUNTER_OTHER: $submissionFile = Services::get('submissionFile')->get($assocId); if ($submissionFile) { $isFile = true; $submissionId = $submissionFile->getData('submissionId'); if ($submissionFile->getData('assocType') == ASSOC_TYPE_REPRESENTATION) { $representationId = $submissionFile->getData('assocId'); } else { throw new Exception('Cannot load record: submission file is not associated with a representation object.'); } } else { throw new Exception('Cannot load record: invalid submission file id.'); } // Don't break but go on to retrieve the representation. case ASSOC_TYPE_REPRESENTATION: if (!$isFile) $representationId = $assocId; $representationDao = Application::getRepresentationDAO(); /* @var $representationDao RepresentationDAO */ $representation = $representationDao->getById($representationId); /* @var $representation Representation */ if ($representation) { if (!$isFile) $isRepresentation = true; $contextId = $representation->getContextId(); $publication = Services::get('publication')->get($representation->getData('publicationId')); $submissionId = $publication->getData('submissionId'); } else { throw new Exception('Cannot load record: invalid representation id.'); } // Don't break but go on to retrieve the submission. case ASSOC_TYPE_SUBMISSION: if (!$isFile && !$isRepresentation) $submissionId = $assocId; $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */ $submission = $submissionDao->getById($submissionId); if ($submission) { $contextId = $submission->getContextId(); $submissionId = $submission->getId(); $sectionId = $submission->getSectionId(); } else { throw new Exception('Cannot load record: invalid submission id.'); } list($assocObjectType, $assocObjectId) = $this->getAssocObjectInfo($submissionId, $contextId); break; case ASSOC_TYPE_SECTION: $sectionDao = Application::getSectionDAO(); $section = $sectionDao->getById($assocId); /* @var $section PKPSection */ if ($section) { $sectionId = $section->getId(); $contextId = $section->getContextId(); } else { throw new Exception('Cannot load record: invalid section id.'); } break; case Application::getContextAssocType(): $contextDao = Application::getContextDAO(); /* @var $contextDao ContextDAO */ $context = $contextDao->getById($assocId); if (!$context) { throw new Exception('Cannot load record: invalid context id.'); } $contextId = $assocId; break; } return array($contextId, $sectionId, $assocObjectType, $assocObjectId, $submissionId, $representationId); } /** * Get the id and type of the object that * the passed submission info is associated with. * Default implementation returns null, subclasses * have to implement it. * @param $submissionId Submission id. * @param $contextId The submission context id. * @return array Assoc type and id of the object. */ protected function getAssocObjectInfo($submissionId, $contextId) { return array(null, null); } }
Simpan