* @license PHP License * @package WB * @subpackage content */ /** * Load base class */ WBClass::load( 'WBContent' ); /** * Content component: Chart * * Display charts * * @version 1.3.0 * @package WB * @subpackage content */ class WBContent_Chart extends WBContent { /** * my parameter list * * - tmpl display template * - action either data, config or template * - chart name of datasource * - datasource datasource directory * - contentdisposition file name for downloads * - requiredgroup access group * - addbom add byte order marker 0xEF, 0xBB, 0xBF * - delimiter of CSV columns * - enclosure of CSV data * - ttl time to live for cached chart data and config (default 24 hours) * * @var array */ protected $config = array( 'tmpl' => 'default', 'action' => 'template', 'chart' => 'default', 'datasource' => 'view', 'requiredgroup' => WBContent::GROUP_ANON, 'contentdisposition' => '', 'addbom' => '0', 'delimiter' => ';', 'enclosure' => '"', 'ttl' => 86400 // 24 h = 12 * 60 * 60 seconds ); /** * Log * @var WBLog */ protected $log; /** * 2nd constructor * * Called after configuration was done */ protected function init() { WBClass::load('WBLog'); $this->log = WBLog::start(__CLASS__); } /** * run * * run component * * @return array parameter list */ public function run() { if (!$this->isUserInGroup($this->config['requiredgroup'])) { $this->loadTemplates('accessDenied'); return $this->config; } $this->config['action'] = strtolower($this->config['action']); if ($this->config['action'] == 'template') { $this->loadTemplates($this->config['tmpl']); $this->tmpl->addGlobalVars($this->config); return $this->config; } if ($this->config['action'] == 'data') { return $this->downloadData(); } if ($this->config['action'] == 'config') { return $this->downloadConfig(); } // this actually won't happen because download exits $this->config['action'] = 'template'; return $this->config; } /** * download data * * */ protected function downloadData() { $randyConf = array( 'addbom' => $this->config['addbom'], 'delimiter' => $this->config['delimiter'], 'enclosure' => $this->config['enclosure'] ); $chart = $this->config['chart']; $ext = 'csv'; $path = $this->getCachePath($chart, $ext, 'data'); $log = array( 'action' => 'download', 'mime' => $ext, 'type' => 'data', 'file' => '', 'size' => 0, 'cache' => 0, ); /** @var WBFile */ $file = null; /** @var WBDatasource_Renderer */ $randy = null; switch ($ext) { case 'json': $mime = 'application/json'; $log['mime'] = 'json'; if ($this->isCacheValid($file, $path)) { $log['cache'] = 1; $log['size'] = $file->getSize(); $log['file'] = $file->basename(); $this->log->notice($log); $this->downloadFile($file->realpath(), $mime, $this->config['contentdisposition']); return; } $randy = WBClass::create('WBDatasource_Renderer_JSON'); break; default: case 'csv': $mime = 'text/csv'; $log['mime'] = 'csv'; if ($this->isCacheValid($file, $path)) { $log['cache'] = 1; $log['size'] = $file->getSize(); $log['file'] = $file->basename(); $this->log->notice($log); $this->downloadFile($file->realpath(), $mime, $this->config['contentdisposition']); return; } $randy = WBClass::create('WBDatasource_Renderer_CSV'); break; } $randy->setConfig($randyConf); /** @var WBDatasource_View */ $view = WBClass::create('WBDatasource_View'); $view->addVars($this->req->export()); $view->setRenderer($randy); $view->render($this->config['datasource'] . '/' . $chart); $rFile = $randy->getFile(); $file->touch($path); $file->rename($rFile->realpath()); $rFile->clear(); $log['size'] = $file->getSize(); $log['file'] = $file->basename(); $this->log->notice($log); $this->downloadFile($file->realpath(), $mime, $this->config['contentdisposition']); } /** * download chart settings * */ protected function downloadConfig() { $chart = $this->config['chart']; $ext = 'xml'; $path = $this->getCachePath($chart, $ext, 'config'); $log = array( 'action' => 'download', 'mime' => $ext, 'type' => 'config', 'file' => '', 'size' => 0, 'cache' => 0, ); /** @var WBFile */ $file = null; switch ($ext) { case 'json': $mime = 'application/json'; $log['mime'] = 'json'; if ($this->isCacheValid($file, $path)) { $file = $file->realpath(); $log['cache'] = 1; break; } $config = WBClass::create('WBConfig'); $config->load('chart/' . $chart); $json = json_encode($config->get('config')); $file->touch($path); $file = $file->realpath(); file_put_contents($file, $json); break; default: case 'xml': $mime = 'text/xml'; $base = WBParam::get('wb/dir/base'); $etc = WBParam::get('wb/dir/config', 'etc'); $file = sprintf('%s/%s/chart/%s.xml', $base, $etc, $chart); if (!file_exists($file)) { $file = sprintf('%s/%s-default/chart/%s.xml', $base, $etc, $chart); } break; } $log['size'] = filesize($file); $log['file'] = basename($file); $this->log->notice($log); $this->downloadFile($file, $mime, $this->config['contentdisposition']); } /** * Make Cache File Path * * Calculate cache path for each chart respecting request parameters * * @param string chart name * @param string file name extension * @param string path for config or data */ private function getCachePath(&$chart, &$ext, $path = 'config') { $ext = 'csv'; $chart = $this->config['chart']; if (strstr($this->config['chart'], '.')) { $name = explode('.', $this->config['chart']); $ext = strtolower(array_pop($name)); $chart = implode('.', $name); } $lang = 'C'; if (class_exists('patI18n', false)) { $lang = patI18n::getLocale(patI18n::LOCALE_TYPE_SHORT); } $log = array( 'action' => 'cachepath', 'mime' => $ext, 'type' => $path, 'file' => '' ); $cs = md5(serialize($this->req->export())); $path = sprintf('var/cache/chart/%s/%s-%s-%s.%s', $path, $chart, $cs, $lang, $ext); $log['file'] = array_pop(explode('/', $path)); $log = array_merge($log, $this->req->export()); $this->log->debug($log); return $path; } /** * Check cache file * * Check if cache file exists and TTL is not exeeded. Also caching parameter will be checked. * * @param WBFile $file * @param string $path * @return bool true if cache is still OK */ private function isCacheValid(&$file, $path) { $file = WBClass::create('WBFile'); if (!$file->exists($path)) { return false; } if (1 > WBParam::get('wb/cache/use', 1)) { return false; } $mTime = filemtime($file->realpath()) + intval($this->config['ttl']); if (time() > $mTime) { return false; } return true; } }