env = $env; $this->app = $app; $this->pos = $pos; $this->searchEngine = $search_engine; $this->query = $query; $this->options = $options; $this->statistics = null; switch ($env) { case "RESULT": if (null === $search_engine) { throw new \LogicException('Search Engine should be provided'); } if (!$options) { $options = new SearchEngineOptions($app['repo.collection-references']); } $options->setFirstResult($pos); $options->setMaxResults(1); $results = $search_engine->query($query, $options); if ($results->getResults()->isEmpty()) { throw new Exception('Record introuvable'); } $this->total = $results->getTotal(); foreach ($results->getResults() as $record) { $number = $pos; $this->original_item = $record; $sbas_id = $record->getDataboxId(); $record_id = $record->getRecordId(); break; } break; case "REG": $contId = explode('_', $contId); $sbas_id = $contId[0]; $record_id = $contId[1]; $this->container = new record_adapter($app, $sbas_id, $record_id); $this->original_item = $this->container; $this->name = $this->container->get_title(['encode'=> record_adapter::ENCODE_NONE]); if ($pos == 0) { $number = 0; } else { $children = $this->container->getChildren(); foreach ($children as $child) { $sbas_id = $child->getDataboxId(); $this->original_item = $child; $record_id = $child->getRecordId(); if ($child->getNumber() == $pos) break; } $number = $pos; $this->total = $children->get_count(); } break; case "BASK": $Basket = $app['converter.basket']->convert($contId); $app['acl.basket']->hasAccess($Basket, $app->getAuthenticatedUser()); $this->container = $Basket; $this->total = $Basket->getElements()->count(); $i = 0; $first = true; foreach ($Basket->getElements() as $element) { $i ++; if ($element->getOrd() == $pos || $first) { $this->original_item = $element; $sbas_id = $element->getSbasId(); $record_id = $element->getRecordId(); $this->name = $Basket->getName(); $number = $element->getOrd(); $first = false; } } break; case "FEED": /** @var FeedEntry $entry */ $entry = $app['repo.feed-entries']->find($contId); $this->container = $entry; $this->total = count($entry->getItems()); $i = 0; $first = true; foreach ($entry->getItems() as $element) { $i ++; if ($element->getOrd() == $pos || $first) { $sbas_id = $element->getSbasId(); $record_id = $element->getRecordId(); $this->name = $entry->getTitle(); $this->original_item = $element; $number = $element->getOrd(); $first = false; } } break; default: throw new InvalidArgumentException(sprintf('Expects env argument to one of (RESULT, REG, BASK, FEED) got %s', $env)); } if (!(isset($sbas_id) && isset($record_id))) { throw new Exception('No record could be found'); } parent::__construct($app, $sbas_id, $record_id, $number); } public function get_train() { if ($this->train) { return $this->train; } switch ($this->env) { case 'RESULT': $options = $this->options ?: new SearchEngineOptions($this->app['repo.collection-references']); $options->setFirstResult(($this->pos - 3) < 0 ? 0 : ($this->pos - 3)); $options->setMaxResults(56); $results = $this->searchEngine->query($this->query, $options); $this->train = $results->getResults()->toArray(); break; case 'BASK': $this->train = $this->container->getElements(); break; case 'REG': $this->train = $this->container->get_children(); break; } return $this->train; } /** * @return bool */ public function is_from_result() { return $this->env == 'RESULT'; } /** * @return bool */ public function is_from_feed() { return $this->env == 'FEED'; } /** * @return bool */ public function is_from_basket() { return $this->env == 'BASK'; } /** * @return bool */ public function is_from_reg() { return $this->env == 'REG'; } public function get_original_item() { return $this->original_item; } public function getEnv() { return $this->env; } /** * @return string */ public function getName(): string { return $this->name; } // PHRAS-3800 : html is now done in twig, so getting parent::get_title is fine // --> no more overload // /** // * // * @return String // */ // public function old_get_title(Array $options = []) // { // if ($this->title) { // return $this->title; // } // // $this->title = ''; // // switch ($this->env) { // // case "RESULT": // $this->title = ''; // $this->title .= $this->app->trans('Resultat %number% / %total%', ['%number%' => '' . $this->formatNumber($this->getNumber() + 1) . '', '%total%' => $this->formatNumber($this->total)]); // $this->title .= ' : ' . parent::get_title($options); // break; // case "BASK": // $this->title = ''; // $this->title .= $this->name . ' (' . $this->formatNumber($this->getNumber()) . ' / ' . $this->formatNumber($this->total) . ') : ' . parent::get_title($options); // // break; // case "REG": // $this->title = ''; // $this->title .= $this->name; // // if ($this->getNumber() != 0) { // $this->title .= sprintf( // ' (%s) : %s',$this->formatNumber($this->getNumber()) . ' / ' . $this->formatNumber($this->total), parent::get_title($options) // ); // } else { // $this->title .= ''; // } // // break; // default: // $this->title .= parent::get_title($options); // break; // } // // return $this->title; // } /** * @return mixed content */ public function get_container() { return $this->container; } /** * @return array */ public function get_short_history() { if ( ! is_null($this->short_history)) { return $this->short_history; } $tab = []; $report = $this->app->getAclForUser($this->app->getAuthenticatedUser()) ->has_right_on_base($this->getBaseId(), \ACL::CANREPORT); $sql = 'SELECT d.* , l.user, l.usrid as usr_id, l.site FROM log_docs d, log l WHERE d.log_id = l.id AND d.record_id = :record_id '; $params = [':record_id' => $this->getRecordId()]; if (! $report) { $sql .= ' AND ((l.usrid = :usr_id AND l.site= :site) OR action="add")'; $params[':usr_id'] = $this->app->getAuthenticatedUser()->getId(); $params[':site'] = $this->app['conf']->get(['main', 'key']); } $sql .= 'ORDER BY d.date, usrid DESC'; foreach ($this->getDataboxConnection()->executeQuery($sql, $params)->fetchAll(PDO::FETCH_ASSOC) as $row) { $hour = $row['date']; if ( ! isset($tab[$hour])) $tab[$hour] = []; $site = $row['site']; if ( ! isset($tab[$hour][$site])) $tab[$hour][$site] = []; $action = $row['action']; if ( ! isset($tab[$hour][$site][$action])) $tab[$hour][$site][$action] = []; if ( ! isset($tab[$hour][$site][$action][$row['usr_id']])) { $tab[$hour][$site][$action][$row['usr_id']] = [ 'final' => [] , 'comment' => [] , 'user' => $row['usr_id'] ? $this->app['repo.users']->find($row['usr_id']) : null ]; } if ( ! in_array($row['final'], $tab[$hour][$site][$action][$row['usr_id']]['final'])) { if ($action == 'collection') { $tab[$hour][$site][$action][$row['usr_id']]['final'][] = phrasea::baseFromColl($this->getDataboxId(), $row['final'], $this->app); } else { $tab[$hour][$site][$action][$row['usr_id']]['final'][] = $row['final']; } } if ( ! in_array($row['comment'], $tab[$hour][$site][$action][$row['usr_id']]['comment'])) $tab[$hour][$site][$action][$row['usr_id']]['comment'][] = $row['comment']; } $this->short_history = array_reverse($tab); return $this->short_history; } /** * get statistics about the record during the last nbDays * - nb of dowloads, nb of views, referrers. * * @param int $nbDays * @return array|bool false if user is not allowed to see stats (aka report) * @throws Exception * @throws \Doctrine\DBAL\DBALException */ public function getStatistics($nbDays) { if(is_null($this->statistics)) { if($nbDays < 1) { throw new \Alchemy\Phrasea\Exception\InvalidArgumentException("nbDays must be > 0"); } if(!$this->app->getAclForUser($this->app->getAuthenticatedUser()) ->has_right_on_base($this->getBaseId(), \ACL::CANREPORT)) { return( ($this->statistics = false) ); } $this->statistics = [ 'days' => $nbDays, 'from' => '', 'to' => '', 'max_views' => 0, 'max_downloads' => 0, 'by_day' => [ // '2012-01-02' => [ // 'label' => '2012-01-02', // 'views' => 123, // 'downloads' => 456, // ], ], 'referrers' => [ 'report::acces direct' => [ 'label' => $this->app->trans('report::acces direct'), 'count' => 0 ], 'admin::monitor: module production' => [ 'label' => $this->app->trans('admin::monitor: module production'), 'count' => 0 ], 'admin::monitor: module client' => [ 'label' => $this->app->trans('admin::monitor: module client'), 'count' => 0 ], 'report:: page d\'accueil' => [ 'label' => $this->app->trans('report:: page d\'accueil'), 'count' => 0 ], 'report:: visualiseur cooliris' => [ 'label' => $this->app->trans('report:: visualiseur cooliris'), 'count' => 0 ], // ... // some more entries can be added if the referrer does not match anything ] ]; // preset 30 dates in the past // $nbDays--; // because 0 is included for ($d=$nbDays; $d>=0; $d--) { $datetime = new DateTime('-' . $d . ' days'); $datetime->modify('+1 day'); $date = date_format($datetime, 'Y-m-d'); if($d == $nbDays) { $this->statistics['from'] = $date; } elseif($d == 0) { $this->statistics['to'] = $date; } $this->statistics['by_day'][$date] = [ 'label' => $date, 'views' => 0, 'downloads' => 0 ]; } //------- views stats // $sql = "SELECT COUNT(id) AS n, DATE_FORMAT(date, '%Y-%m-%d') AS datee FROM `log_view`\n" . " WHERE record_id = :record_id\n" . " AND date >= :from AND date <= :to\n" . " AND site_id = :site\n" . " GROUP BY datee ORDER BY datee ASC"; $result = $this->getDataboxConnection() ->executeQuery($sql, [ ':record_id' => $this->getRecordId(), ':site' => $this->app['conf']->get(['main', 'key']), ':from' => $this->statistics['from'], ':to' => $this->statistics['to'] ]) ->fetchAll(PDO::FETCH_ASSOC); foreach ($result as $row) { $date = $row['datee']; if(array_key_exists($date, $this->statistics['by_day'])) { $this->statistics['by_day'][$date]['views'] += (int)($row['n']); if($this->statistics['by_day'][$date]['views'] > $this->statistics['max_views']) { $this->statistics['max_views'] = $this->statistics['by_day'][$date]['views']; } } } //------- downloads stats // $sql = "SELECT COUNT(d.id) AS n, DATE_FORMAT(d.date, '%Y-%m-%d') AS datee\n" . " FROM `log_docs` AS d, log AS l\n" . " WHERE action='download'\n" . " AND log_id=l.id\n" . " AND record_id= :record_id\n" . " AND d.date >= :from AND d.date <= :to\n" . " AND site= :site\n" . " GROUP BY datee ORDER BY datee ASC"; $result = $this->getDataboxConnection() ->executeQuery($sql, [ ':record_id' => $this->getRecordId(), ':site' => $this->app['conf']->get(['main', 'key']), ':from' => $this->statistics['from'], ':to' => $this->statistics['to'] ]) ->fetchAll(PDO::FETCH_ASSOC); foreach ($result as $row) { $date = $row['datee']; if(array_key_exists($date, $this->statistics['by_day'])) { $this->statistics['by_day'][$date]['downloads'] += (int)($row['n']); if($this->statistics['by_day'][$date]['downloads'] > $this->statistics['max_downloads']) { $this->statistics['max_downloads'] = $this->statistics['by_day'][$date]['downloads']; } } } //------- referers stats // $sql = "SELECT count( id ) AS n, referrer FROM `log_view`\n" . " WHERE record_id = :record_id\n" . " AND date >= :from AND date <= :to\n" . " GROUP BY referrer ORDER BY referrer ASC"; $result = $this->getDataboxConnection() ->executeQuery($sql, [ ':record_id' => $this->getRecordId(), ':from' => $this->statistics['from'], ':to' => $this->statistics['to'] ]) ->fetchAll(PDO::FETCH_ASSOC); foreach ($result as $row) { $k = $row['referrer']; if ($k == 'NO REFERRER') { $k = $this->app->trans('report::acces direct'); } elseif ($k == $this->app['conf']->get('servername') . 'prod/') { $k = $this->app->trans('admin::monitor: module production'); } elseif ($k == $this->app['conf']->get('servername') . 'client/') { $k = $this->app->trans('admin::monitor: module client'); } elseif (strpos($k, 'http://apps.cooliris.com/') !== false) { $k = $this->app->trans('report:: visualiseur cooliris'); } elseif (strpos($k, $this->app['conf']->get('servername') . 'login/') !== false) { $k = $this->app->trans('report:: page d\'accueil'); } elseif (strpos($k, $this->app['conf']->get('servername') . 'document/') !== false) { $k = $this->app->trans('report::acces direct'); } elseif (strpos($k, $this->app['conf']->get('servername') . 'permalink/') !== false) { $k = $this->app->trans('report::acces direct'); } if (!isset($this->statistics['referrers'][$k])) { // the referrer does not match anything, just add it untranslated $this->statistics['referrers'][$k] = [ 'label' => $k, 'count' => 0 ]; } $this->statistics['referrers'][$k]['count'] += (int)$row['n']; } } return $this->statistics; } /** * @return int */ public function getTotal() { return isset($this->total) ? $this->total : 0; } /** * @return media_adapter */ public function get_view_popularity() { if ( ! is_null($this->view_popularity)) { return $this->view_popularity; } $report = $this->app->getAclForUser($this->app->getAuthenticatedUser()) ->has_right_on_base($this->getBaseId(), \ACL::CANREPORT); if ( ! $report && ! $this->app['conf']->get(['registry', 'webservices', 'google-charts-enabled'])) { $this->view_popularity = false; return $this->view_popularity; } $views = $dwnls = []; $top = 1; $day = 30; $min = 0; $average = 0; while ($day >= 0) { $datetime = new DateTime('-' . $day . ' days'); $date = date_format($datetime, 'Y-m-d'); $views[$date] = $dwnls[$date] = 0; $day --; } $sql = 'SELECT count(id) as views, DATE(date) as datee FROM `log_view` WHERE record_id = :record_id AND date > (NOW() - INTERVAL 1 MONTH) AND site_id = :site GROUP BY datee ORDER BY datee ASC'; $result = $this->getDataboxConnection() ->executeQuery($sql, [ ':record_id' => $this->getRecordId(), ':site' => $this->app['conf']->get(['main', 'key']) ]) ->fetchAll(PDO::FETCH_ASSOC); foreach ($result as $row) { if (isset($views[$row['datee']])) { $views[$row['datee']] = (int) $row['views']; $top = max((int) $row['views'], $top); $min = isset($min) ? min($row['views'], $min) : $row['views']; $average += $row['views']; } } $topScale = round($top * 1.2); $average = $average / 30; $max = round(($top) * 100 / ($topScale)); $min = round($min * 100 / ($topScale)); $average = round($average * 100 / ($topScale)); $width = 350; $height = 150; $url = Url::factory('https://chart.googleapis.com/chart?' . 'chs=' . $width . 'x' . $height . '&chd=t:' . implode(',', $views) . '&cht=lc' . '&chf=bg,s,00000000' . '&chxt=x,y,r' . '&chds=0,' . $topScale . '&chls=2.0&chxtc=2,-350' . '&chxl=0:|' . date_format(new DateTime('-30 days'), 'd M') . '|' . date_format(new DateTime('-15 days'), 'd M') . '|' . date_format(new DateTime(), 'd M') . '|1:|0|' . round($top / 2, 2) . '|' . $top . '|2:|min|average|max' . '&chxp=2,' . $min . ',' . $average . ',' . $max); $this->view_popularity = new media_adapter($width, $height, $url); return $this->view_popularity; } /** * @return media_adapter */ public function get_refferer_popularity() { if ( ! is_null($this->refferer_popularity)) { return $this->refferer_popularity; } $report = $this->app->getAclForUser($this->app->getAuthenticatedUser()) ->has_right_on_base($this->getBaseId(), \ACL::CANREPORT); if ( ! $report && ! $this->app['conf']->get(['registry', 'webservices', 'google-charts-enabled'])) { $this->refferer_popularity = false; return $this->refferer_popularity; } $sql = 'SELECT count( id ) AS views, referrer FROM `log_view` WHERE record_id = :record_id AND date > ( NOW( ) - INTERVAL 1 MONTH ) GROUP BY referrer ORDER BY referrer ASC'; $result = $this->getDataboxConnection() ->executeQuery($sql, [':record_id' => $this->getRecordId()]) ->fetchAll(PDO::FETCH_ASSOC); $referrers = []; foreach ($result as $row) { if ($row['referrer'] == 'NO REFERRER') $row['referrer'] = $this->app->trans('report::acces direct'); if ($row['referrer'] == $this->app['conf']->get('servername') . 'prod/') $row['referrer'] = $this->app->trans('admin::monitor: module production'); if ($row['referrer'] == $this->app['conf']->get('servername') . 'client/') $row['referrer'] = $this->app->trans('admin::monitor: module client'); if (strpos($row['referrer'], $this->app['conf']->get('servername') . 'login/') !== false) $row['referrer'] = $this->app->trans('report:: page d\'accueil'); if (strpos($row['referrer'], 'http://apps.cooliris.com/') !== false) $row['referrer'] = $this->app->trans('report:: visualiseur cooliris'); if (strpos($row['referrer'], $this->app['conf']->get('servername') . 'document/') !== false) { $row['referrer'] = $this->app->trans('report::acces direct'); } if (strpos($row['referrer'], $this->app['conf']->get('servername') . 'permalink/') !== false) { $row['referrer'] = $this->app->trans('report::acces direct'); } if ( ! isset($referrers[$row['referrer']])) $referrers[$row['referrer']] = 0; $referrers[$row['referrer']] += (int) $row['views']; } $width = 550; $height = 100; $url = Url::factory('https://chart.googleapis.com/chart?' . 'cht=p3&chf=bg,s,00000000&chd=t:' . implode(',', $referrers) . '&chs=' . $width . 'x' . $height . '&chl=' . urlencode(implode('|', array_keys($referrers)))); $this->refferer_popularity = new media_adapter($width, $height, $url); return $this->refferer_popularity; } /** * @return media_adapter */ public function get_download_popularity() { if ( ! is_null($this->download_popularity)) { return $this->download_popularity; } $report = $this->app->getAclForUser($this->app->getAuthenticatedUser()) ->has_right_on_base($this->getBaseId(), \ACL::CANREPORT); $ret = false; if ( ! $report && ! $this->app['conf']->get(['registry', 'webservices', 'google-charts-enabled'])) { $this->download_popularity = false; return $this->download_popularity; } $views = $dwnls = []; $top = 1; $day = 30; while ($day >= 0) { $datetime = new DateTime('-' . $day . ' days'); $date = date_format($datetime, 'Y-m-d'); $views[$date] = $dwnls[$date] = 0; $day --; } $sql = 'SELECT count(d.id) as dwnl, DATE(d.date) as datee FROM `log_docs` d, log l WHERE action="download" AND log_id=l.id AND record_id= :record_id AND d.date > (NOW() - INTERVAL 1 MONTH) AND site= :site GROUP BY datee ORDER BY datee ASC'; $result = $this->getDataboxConnection() ->executeQuery($sql, [ ':record_id' => $this->getRecordId(), ':site' => $this->app['conf']->get(['main', 'key']) ]) ->fetchAll(PDO::FETCH_ASSOC); $top = 10; foreach ($result as $row) { if (isset($dwnls[$row['datee']])) { $dwnls[$row['datee']] = (int) $row['dwnl']; $top = max(((int) $row['dwnl'] + 10), $top); } } $width = 250; $height = 150; $url = Url::factory('https://chart.googleapis.com/chart?' . 'chs=' . $width . 'x' . $height . '&chd=t:' . implode(',', $dwnls) . '&cht=lc' . '&chf=bg,s,00000000' . '&chxt=x,y' . '&chds=0,' . $top . '&chxl=0:|' . date_format(new DateTime('-30 days'), 'd M') . '|' . date_format(new DateTime('-15 days'), 'd M') . '|' . date_format(new DateTime(), 'd M') . '|1:|0|' . round($top / 2) . '|' . $top); $ret = new media_adapter($width, $height, $url); $this->download_popularity = $ret; return $this->download_popularity; } public function formatNumber($number) { return number_format($number, 0, null, ' '); } }