| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\API; |
|
|
| use Exception; |
| use Piwik\Common; |
| use Piwik\DataTable; |
| use Piwik\DataTable\DataTableInterface; |
| use Piwik\DataTable\Filter\ColumnDelete; |
| use Piwik\DataTable\Filter\Pattern; |
| use Piwik\DataTable\Renderer; |
| use Piwik\ExceptionHandler; |
| use Piwik\Http\HttpCodeException; |
| use Piwik\Plugin\ReportsProvider; |
| use Piwik\Plugins\Monolog\Processor\ExceptionToTextProcessor; |
| use Piwik\Plugins\PrivacyManager\DataRounding; |
|
|
| class ResponseBuilder |
| { |
| private $outputFormat = null; |
| private $apiRenderer = null; |
| private $request = null; |
| private $sendHeader = true; |
| private $postProcessDataTable = true; |
|
|
| private $apiModule = false; |
| private $apiMethod = false; |
| private $shouldPrintBacktrace = false; |
|
|
| |
| |
| |
| |
| |
| public function __construct($outputFormat, $request = array(), $shouldPrintBacktrace = null) |
| { |
| $this->outputFormat = $outputFormat; |
| $this->request = $request; |
| $this->apiRenderer = ApiRenderer::factory($outputFormat, $request); |
| $this->shouldPrintBacktrace = $shouldPrintBacktrace === null ? ExceptionHandler::shouldPrintBackTraceWithMessage() : $shouldPrintBacktrace; |
| } |
|
|
| public function disableSendHeader() |
| { |
| $this->sendHeader = false; |
| } |
|
|
| public function disableDataTablePostProcessor() |
| { |
| $this->postProcessDataTable = false; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getResponse($value = null, $apiModule = false, $apiMethod = false) |
| { |
| $this->apiModule = $apiModule; |
| $this->apiMethod = $apiMethod; |
|
|
| $this->sendHeaderIfEnabled(); |
|
|
| |
| if (!isset($value)) { |
| if (ob_get_contents()) { |
| return null; |
| } |
|
|
| return $this->apiRenderer->renderSuccess('ok'); |
| } |
|
|
| |
| |
| |
| if ($value instanceof DataTableInterface) { |
| return $this->handleDataTable($value); |
| } |
|
|
| |
| |
| |
| |
| |
| if (is_array($value)) { |
| return $this->handleArray($value); |
| } |
|
|
| if (is_object($value)) { |
| return $this->apiRenderer->renderObject($value); |
| } |
|
|
| if (is_resource($value)) { |
| return $this->apiRenderer->renderResource($value); |
| } |
|
|
| return $this->apiRenderer->renderScalar($value); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function getResponseException($e) |
| { |
| $e = $this->decorateExceptionWithDebugTrace($e); |
| $message = $this->formatExceptionMessage($e); |
|
|
| if ( |
| $this->sendHeader |
| && $e instanceof HttpCodeException |
| && $e->getCode() > 0 |
| ) { |
| http_response_code($e->getCode()); |
| } |
|
|
| $this->sendHeaderIfEnabled(); |
|
|
| return $this->apiRenderer->renderException($message, $e); |
| } |
|
|
| |
| |
| |
| |
| private function decorateExceptionWithDebugTrace($e) |
| { |
| |
| if (defined('PIWIK_PATH_TEST_TO_ROOT')) { |
| if ($this->shouldPrintBacktrace) { |
| $message = $e->getMessage() . " in \n " . $e->getFile() . ":" . $e->getLine() . " \n " . $e->getTraceAsString(); |
| } else { |
| $message = $e->getMessage() . "\n \n --> To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php"; |
| } |
|
|
| return new Exception($message); |
| } |
|
|
| return $e; |
| } |
|
|
| |
| |
| |
| |
| private function formatExceptionMessage($exception) |
| { |
| $message = ExceptionToTextProcessor::getMessageAndWholeBacktrace($exception, $this->shouldPrintBacktrace); |
|
|
| if ($exception instanceof \Piwik\Exception\Exception && $exception->isHtmlMessage() && Request::isRootRequestApiRequest()) { |
| $message = strip_tags(str_replace('<br />', PHP_EOL, $message)); |
| } |
|
|
| return Renderer::formatValueXml($message); |
| } |
|
|
| private function handleDataTable(DataTableInterface $datatable) |
| { |
| if ($this->postProcessDataTable) { |
| $postProcessor = new DataTablePostProcessor($this->apiModule, $this->apiMethod, $this->request); |
| $datatable = $postProcessor->process($datatable); |
| } else { |
| $report = null; |
| if ( |
| DataRounding::shouldApplyForRequest($this->request) |
| && !empty($this->apiModule) |
| && !empty($this->apiMethod) |
| ) { |
| $report = ReportsProvider::factory($this->apiModule, $this->apiMethod); |
| } |
|
|
| DataRounding::roundCountMetricsForRequest($datatable, $this->request, $report); |
| } |
|
|
| return $this->apiRenderer->renderDataTable($datatable); |
| } |
|
|
| private function handleArray($array) |
| { |
| if (!$this->shouldSkipRequestBasedArrayRounding() && DataRounding::shouldApplyForRequest($this->request)) { |
| $array = DataRounding::roundCountArrayValuesForRequest($array, $this->request); |
| } |
|
|
| $firstArray = null; |
| $firstKey = null; |
| if (!empty($array)) { |
| $firstArray = reset($array); |
| $firstKey = key($array); |
| } |
|
|
| $isAssoc = !empty($firstArray) && is_numeric($firstKey) && is_array($firstArray) && count(array_filter(array_keys($firstArray), 'is_string')); |
|
|
| if (is_numeric($firstKey)) { |
| $columns = Common::getRequestVar('filter_column', false, 'array', $this->request); |
| $pattern = Common::getRequestVar('filter_pattern', '', 'string', $this->request); |
|
|
| if ($columns != array(false) && $pattern !== '') { |
| $pattern = new Pattern(new DataTable(), $columns, $pattern); |
| $array = $pattern->filterArray($array); |
| } |
|
|
| $limit = Common::getRequestVar('filter_limit', -1, 'integer', $this->request); |
| $offset = Common::getRequestVar('filter_offset', '0', 'integer', $this->request); |
|
|
| if ($limit >= 0 || $offset > 0) { |
| if ($limit < 0) { |
| $limit = null; |
| } |
| $array = array_slice($array, $offset, $limit, $preserveKeys = false); |
| } |
| } |
|
|
| if ($isAssoc) { |
| $hideColumns = Common::getRequestVar('hideColumns', '', 'string', $this->request); |
| $showColumns = Common::getRequestVar('showColumns', '', 'string', $this->request); |
| if ($hideColumns !== '' || $showColumns !== '') { |
| $columnDelete = new ColumnDelete(new DataTable(), $hideColumns, $showColumns); |
| $array = $columnDelete->filter($array); |
| } |
| } |
|
|
| return $this->apiRenderer->renderArray($array); |
| } |
|
|
| private function shouldSkipRequestBasedArrayRounding(): bool |
| { |
| |
| |
| return $this->apiModule === 'MultiSites' && $this->apiMethod === 'getAllWithGroups'; |
| } |
|
|
| private function sendHeaderIfEnabled() |
| { |
| if ($this->sendHeader) { |
| $this->apiRenderer->sendHeader(); |
| } |
| } |
| } |
|
|