From e3a872ba0f7231a1a98c5812f491e6c3fdeb1dd8 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Wed, 11 Feb 2026 17:55:16 +0100 Subject: [PATCH 1/2] fix: hack to get the attributes as an array instead of an object --- src/Backend/Modules/Locale/Engine/Model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Backend/Modules/Locale/Engine/Model.php b/src/Backend/Modules/Locale/Engine/Model.php index f69de34d08..0e33c4b328 100644 --- a/src/Backend/Modules/Locale/Engine/Model.php +++ b/src/Backend/Modules/Locale/Engine/Model.php @@ -476,7 +476,7 @@ public static function importXML( // items foreach ($items as $item) { // attributes - $attributes = $item->attributes(); + $attributes = current($item->attributes()); $type = in_array($attributes['type'], $possibleTypes, true) ? $attributes['type'] : ''; $name = s($attributes['name'] ?? '')->title()->toString(); @@ -494,7 +494,7 @@ public static function importXML( ++$statistics['total']; // attributes - $attributes = $translation->attributes(); + $attributes = current($translation->attributes()); $language = in_array($attributes['language'], $possibleLanguages[$application], true) ? $attributes['language'] : ''; // language does not exist From 4a70c36956987c03d0013f82d0c6b97be1a91010 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Wed, 11 Feb 2026 18:02:52 +0100 Subject: [PATCH 2/2] feat: Remove Analytics module --- package.json | 1 - phpunit.xml.dist | 1 - src/Backend/Core/Installer/Data/locale.xml | 18 - src/Backend/Core/Js/backend.js | 4 - .../Modules/Analytics/Actions/Index.php | 85 ----- .../Modules/Analytics/Actions/Reset.php | 25 -- .../Modules/Analytics/Actions/Settings.php | 45 --- src/Backend/Modules/Analytics/Config.php | 12 - .../Modules/Analytics/DateRange/DateRange.php | 45 --- .../AnalyticsExtension.php | 22 -- .../Modules/Analytics/Form/DateRangeType.php | 110 ------ .../Form/SettingsStepAccountTypeInterface.php | 85 ----- ...ettingsStepAuthConfigFileTypeInterface.php | 73 ---- .../Form/SettingsStepProfileTypeInterface.php | 71 ---- .../Form/SettingsStepTypeInterface.php | 15 - .../SettingsStepWebPropertyTypeInterface.php | 70 ---- .../Modules/Analytics/Form/SettingsType.php | 67 ---- .../Analytics/GoogleClient/ClientFactory.php | 47 --- .../Analytics/GoogleClient/Connector.php | 336 ------------------ .../Analytics/Installer/Data/locale.xml | 313 ---------------- .../Modules/Analytics/Installer/Installer.php | 47 --- src/Backend/Modules/Analytics/Js/Analytics.js | 190 ---------- .../Layout/Templates/Index.html.twig | 138 ------- .../Layout/Templates/Settings.html.twig | 132 ------- .../Layout/Widgets/RecentVisits.html.twig | 48 --- .../Layout/Widgets/TraficSources.html.twig | 26 -- .../Analytics/Resources/config/services.yml | 23 -- .../Analytics/Tests/Actions/IndexTest.php | 25 -- .../Analytics/Tests/Actions/ResetTest.php | 25 -- .../Analytics/Tests/Actions/SettingsTest.php | 21 -- .../Tests/GoogleClient/ConnectorTest.php | 292 --------------- .../Analytics/Widgets/RecentVisits.php | 36 -- .../Analytics/Widgets/TraficSources.php | 36 -- src/Backend/Modules/Analytics/info.xml | 21 -- .../Modules/Settings/Actions/Index.php | 2 +- tests/data/test_db.sql | 108 ------ 36 files changed, 1 insertion(+), 2614 deletions(-) delete mode 100644 src/Backend/Modules/Analytics/Actions/Index.php delete mode 100644 src/Backend/Modules/Analytics/Actions/Reset.php delete mode 100644 src/Backend/Modules/Analytics/Actions/Settings.php delete mode 100644 src/Backend/Modules/Analytics/Config.php delete mode 100644 src/Backend/Modules/Analytics/DateRange/DateRange.php delete mode 100644 src/Backend/Modules/Analytics/DependencyInjection/AnalyticsExtension.php delete mode 100644 src/Backend/Modules/Analytics/Form/DateRangeType.php delete mode 100644 src/Backend/Modules/Analytics/Form/SettingsStepAccountTypeInterface.php delete mode 100644 src/Backend/Modules/Analytics/Form/SettingsStepAuthConfigFileTypeInterface.php delete mode 100644 src/Backend/Modules/Analytics/Form/SettingsStepProfileTypeInterface.php delete mode 100644 src/Backend/Modules/Analytics/Form/SettingsStepTypeInterface.php delete mode 100644 src/Backend/Modules/Analytics/Form/SettingsStepWebPropertyTypeInterface.php delete mode 100644 src/Backend/Modules/Analytics/Form/SettingsType.php delete mode 100644 src/Backend/Modules/Analytics/GoogleClient/ClientFactory.php delete mode 100644 src/Backend/Modules/Analytics/GoogleClient/Connector.php delete mode 100644 src/Backend/Modules/Analytics/Installer/Data/locale.xml delete mode 100644 src/Backend/Modules/Analytics/Installer/Installer.php delete mode 100644 src/Backend/Modules/Analytics/Js/Analytics.js delete mode 100644 src/Backend/Modules/Analytics/Layout/Templates/Index.html.twig delete mode 100644 src/Backend/Modules/Analytics/Layout/Templates/Settings.html.twig delete mode 100644 src/Backend/Modules/Analytics/Layout/Widgets/RecentVisits.html.twig delete mode 100644 src/Backend/Modules/Analytics/Layout/Widgets/TraficSources.html.twig delete mode 100644 src/Backend/Modules/Analytics/Resources/config/services.yml delete mode 100644 src/Backend/Modules/Analytics/Tests/Actions/IndexTest.php delete mode 100644 src/Backend/Modules/Analytics/Tests/Actions/ResetTest.php delete mode 100644 src/Backend/Modules/Analytics/Tests/Actions/SettingsTest.php delete mode 100644 src/Backend/Modules/Analytics/Tests/GoogleClient/ConnectorTest.php delete mode 100644 src/Backend/Modules/Analytics/Widgets/RecentVisits.php delete mode 100644 src/Backend/Modules/Analytics/Widgets/TraficSources.php delete mode 100644 src/Backend/Modules/Analytics/info.xml diff --git a/package.json b/package.json index 23e5543fa9..256f3e5009 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,6 @@ "src/Backend/Core/Js/jquery/jquery.backend.js", "src/Backend/Core/Js/jquery/jquery.ui.dialog.patch.js", "src/Backend/Core/Js/utils.js", - "src/Backend/Modules/Analytics/Js/Analytics.js", "src/Backend/Modules/Blog/Js/Blog.js", "src/Backend/Modules/Extensions/Js/Modules.js", "src/Backend/Modules/Extensions/Js/ThemeTemplate.js", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d6e71bb043..9c1323a918 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -61,7 +61,6 @@ src/Frontend/Modules/Profiles/Tests/Actions src/Frontend/Modules/Search/Tests/Actions src/Frontend/Modules/Tags/Tests/Actions - src/Backend/Modules/Analytics/Tests/Actions src/Backend/Modules/Authentication/Tests/Actions src/Backend/Modules/Blog/Tests/Actions src/Backend/Modules/ContentBlocks/Tests/Actions diff --git a/src/Backend/Core/Installer/Data/locale.xml b/src/Backend/Core/Installer/Data/locale.xml index dc1f961a32..919eb6c827 100644 --- a/src/Backend/Core/Installer/Data/locale.xml +++ b/src/Backend/Core/Installer/Data/locale.xml @@ -4836,24 +4836,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/Backend/Core/Js/backend.js b/src/Backend/Core/Js/backend.js index 820f16b986..bda7c2529e 100644 --- a/src/Backend/Core/Js/backend.js +++ b/src/Backend/Core/Js/backend.js @@ -2045,10 +2045,6 @@ jsBackend.resizeFunctions = { calculate = (function (_this) { return function () { jsBackend.navigation.resize() - if (typeof jsBackend.analytics !== 'undefined') { - jsBackend.analytics.chartDoubleMetricPerDay.init() - jsBackend.analytics.chartPieChart.init() - } ticking = false } })(this) diff --git a/src/Backend/Modules/Analytics/Actions/Index.php b/src/Backend/Modules/Analytics/Actions/Index.php deleted file mode 100644 index 1ed8c1d81f..0000000000 --- a/src/Backend/Modules/Analytics/Actions/Index.php +++ /dev/null @@ -1,85 +0,0 @@ -dateRange = new DateRange(); - - $this->handleDateRangeForm(); - $this->parse(); - $this->display(); - } - - /** - * The form will update the date range filter if needed - */ - private function handleDateRangeForm(): void - { - $dateRangeForm = new DateRangeType('date_range', $this->dateRange); - - if ($dateRangeForm->handle()) { - $this->dateRange = $dateRangeForm->getDateRange(); - } - - $dateRangeForm->parse($this->template); - } - - protected function parse(): void - { - parent::parse(); - - // if we don't have a token anymore, redirect to the settings page - if ($this->get('fork.settings')->get($this->getModule(), 'certificate') === null - || $this->get('fork.settings')->get($this->getModule(), 'account') === null - || $this->get('fork.settings')->get($this->getModule(), 'web_property_id') === null - || $this->get('fork.settings')->get($this->getModule(), 'profile') === null - ) { - $this->redirect(Model::createUrlForAction('Settings')); - } - - $this->header->addJS('highcharts.js', 'Core', false); - $analytics = $this->get('analytics.connector'); - $analyticsTemplateToFunctionMap = [ - 'page_views' => 'getPageViews', - 'visitors' => 'getVisitors', - 'pages_per_visit' => 'getPagesPerVisit', - 'time_on_site' => 'getTimeOnSite', - 'new_sessions_percentage' => 'getNewSessionsPercentage', - 'bounce_rate' => 'getBounceRate', - 'visitors_graph_data' => 'getVisitorsGraphData', - 'source_graph_data' => 'getSourceGraphData', - ]; - - foreach ($analyticsTemplateToFunctionMap as $templateVariableName => $functionName) { - $this->template->assign( - $templateVariableName, - $analytics->$functionName($this->dateRange->getStartDate(), $this->dateRange->getEndDate()) - ); - } - - $dataGrid = new DataGridArray( - $analytics->getMostVisitedPagesData($this->dateRange->getStartDate(), $this->dateRange->getEndDate()) - ); - $this->template->assign('dataGridMostViewedPages', $dataGrid->getContent()); - } -} diff --git a/src/Backend/Modules/Analytics/Actions/Reset.php b/src/Backend/Modules/Analytics/Actions/Reset.php deleted file mode 100644 index 823356e4be..0000000000 --- a/src/Backend/Modules/Analytics/Actions/Reset.php +++ /dev/null @@ -1,25 +0,0 @@ -checkToken(); - - $this->get('fork.settings')->delete($this->getModule(), 'certificate'); - $this->get('fork.settings')->delete($this->getModule(), 'email'); - $this->get('fork.settings')->delete($this->getModule(), 'account'); - $this->get('fork.settings')->delete($this->getModule(), 'web_property_id'); - $this->get('fork.settings')->delete($this->getModule(), 'profile'); - - $this->redirect(Model::createUrlForAction('Settings')); - } -} diff --git a/src/Backend/Modules/Analytics/Actions/Settings.php b/src/Backend/Modules/Analytics/Actions/Settings.php deleted file mode 100644 index 1d7b154dd8..0000000000 --- a/src/Backend/Modules/Analytics/Actions/Settings.php +++ /dev/null @@ -1,45 +0,0 @@ -get('fork.settings'), - $this->get('analytics.google_analytics_service') - ); - - if ($settingsForm->handle()) { - $this->redirect(Model::createUrlForAction('Settings')); - } - $settingsForm->parse($this->template); - - if ($this->get('fork.settings')->get($this->getModule(), 'web_property_id')) { - $this->template->assign( - 'web_property_id', - $this->get('fork.settings')->get($this->getModule(), 'web_property_id') - ); - } - if ($this->get('fork.settings')->get($this->getModule(), 'profile')) { - $this->template->assign( - 'profile', - $this->get('fork.settings')->get($this->getModule(), 'profile') - ); - } - - $this->display(); - } -} diff --git a/src/Backend/Modules/Analytics/Config.php b/src/Backend/Modules/Analytics/Config.php deleted file mode 100644 index 446f1686c9..0000000000 --- a/src/Backend/Modules/Analytics/Config.php +++ /dev/null @@ -1,12 +0,0 @@ -startDate = strtotime('-1 week', mktime(0, 0, 0)); - $this->endDate = mktime(0, 0, 0); - } - - public function update(int $startDate, int $endDate): void - { - $this->startDate = $startDate; - $this->endDate = $endDate; - } - - public function getStartDate(): int - { - return $this->startDate; - } - - public function getEndDate(): int - { - return $this->endDate; - } -} diff --git a/src/Backend/Modules/Analytics/DependencyInjection/AnalyticsExtension.php b/src/Backend/Modules/Analytics/DependencyInjection/AnalyticsExtension.php deleted file mode 100644 index 8c8f7b2926..0000000000 --- a/src/Backend/Modules/Analytics/DependencyInjection/AnalyticsExtension.php +++ /dev/null @@ -1,22 +0,0 @@ -load('services.yml'); - } -} diff --git a/src/Backend/Modules/Analytics/Form/DateRangeType.php b/src/Backend/Modules/Analytics/Form/DateRangeType.php deleted file mode 100644 index 152fac1582..0000000000 --- a/src/Backend/Modules/Analytics/Form/DateRangeType.php +++ /dev/null @@ -1,110 +0,0 @@ -form = new Form($name); - - $this->build(); - } - - public function parse(TwigTemplate $template): void - { - $this->form->parse($template); - $template->assign('startTimestamp', $this->dateRange->getStartDate()); - $template->assign('endTimestamp', $this->dateRange->getEndDate()); - } - - public function handle(): bool - { - $this->form->cleanupFields(); - - if (!$this->form->isSubmitted() || !$this->isValid()) { - return false; - } - - $fields = $this->form->getFields(); - - $newStartDate = Model::getUTCTimestamp($fields['start_date']); - $newEndDate = Model::getUTCTimestamp($fields['end_date']); - - $this->dateRange->update($newStartDate, $newEndDate); - - return true; - } - - private function build(): void - { - $this->form->addDate( - 'start_date', - $this->dateRange->getStartDate(), - 'range', - mktime(0, 0, 0, 1, 1, 2005), - time() - ); - $this->form->addDate( - 'end_date', - $this->dateRange->getEndDate(), - 'range', - mktime(0, 0, 0, 1, 1, 2005), - time() - ); - } - - private function isValid(): bool - { - $fields = $this->form->getFields(); - - if (!$fields['start_date']->isFilled(Language::err('FieldIsRequired')) || - !$fields['end_date']->isFilled(Language::err('FieldIsRequired')) - ) { - return $this->form->isCorrect(); - } - - if (!$fields['start_date']->isValid(Language::err('DateIsInvalid')) || - !$fields['end_date']->isValid(Language::err('DateIsInvalid')) - ) { - return $this->form->isCorrect(); - } - - $newStartDate = Model::getUTCTimestamp($fields['start_date']); - $newEndDate = Model::getUTCTimestamp($fields['end_date']); - - // startdate cannot be before 2005 (earliest valid google startdate) - if ($newStartDate < mktime(0, 0, 0, 1, 1, 2005)) { - $fields['start_date']->setError(Language::err('DateRangeIsInvalid')); - } - - // enddate cannot be in the future - if ($newEndDate > time()) { - $fields['start_date']->setError(Language::err('DateRangeIsInvalid')); - } - - // enddate cannot be before the startdate - if ($newStartDate > $newEndDate) { - $fields['start_date']->setError(Language::err('DateRangeIsInvalid')); - } - - return $this->form->isCorrect(); - } - - public function getDateRange(): DateRange - { - return $this->dateRange; - } -} diff --git a/src/Backend/Modules/Analytics/Form/SettingsStepAccountTypeInterface.php b/src/Backend/Modules/Analytics/Form/SettingsStepAccountTypeInterface.php deleted file mode 100644 index 480171d0bd..0000000000 --- a/src/Backend/Modules/Analytics/Form/SettingsStepAccountTypeInterface.php +++ /dev/null @@ -1,85 +0,0 @@ -form = new Form($name); - - $this->build(); - } - - public function parse(TwigTemplate $template): void - { - if (!$this->hasAccounts) { - $template->assign('email', $this->settings->get('Analytics', 'email')); - $template->assign('noAccounts', true); - } - - $this->form->parse($template); - } - - public function handle(): bool - { - $this->form->cleanupFields(); - - if (!$this->form->isSubmitted() || !$this->isValid()) { - return false; - } - - $this->settings->set( - 'Analytics', - 'account', - $this->form->getField('account')->getValue() - ); - - return true; - } - - private function build(): void - { - try { - $accounts = $this->googleServiceAnalytics->management_accounts->listManagementAccounts(); - } catch (Google_Service_Exception) { - $this->hasAccounts = false; - - return; - } - - $accountsForDropDown = []; - foreach ($accounts->getItems() as $account) { - $accountsForDropDown[$account->getId()] = $account->getName(); - } - $this->form->addDropdown('account', $accountsForDropDown); - - $this->hasAccounts = true; - } - - private function isValid(): bool - { - $this->form->getField('account')->isFilled(Language::err('FieldIsRequired')); - - return $this->form->isCorrect(); - } -} diff --git a/src/Backend/Modules/Analytics/Form/SettingsStepAuthConfigFileTypeInterface.php b/src/Backend/Modules/Analytics/Form/SettingsStepAuthConfigFileTypeInterface.php deleted file mode 100644 index b042d76fb1..0000000000 --- a/src/Backend/Modules/Analytics/Form/SettingsStepAuthConfigFileTypeInterface.php +++ /dev/null @@ -1,73 +0,0 @@ -form = new Form($name); - - $this->build(); - } - - public function parse(TwigTemplate $template): void - { - $this->form->parse($template); - } - - public function handle(): bool - { - $this->form->cleanupFields(); - - if (!$this->form->isSubmitted() || !$this->isValid()) { - return false; - } - - $certificate = base64_encode(file_get_contents($this->form->getField('certificate')->getTempFileName())); - - $this->settings->set( - 'Analytics', - 'certificate', - $certificate - ); - $this->settings->set( - 'Analytics', - 'email', - $this->form->getField('email')->getValue() - ); - - return true; - } - - private function build(): void - { - $this->form->addFile('certificate'); - $this->form->addText('email'); - } - - private function isValid(): bool - { - $fileField = $this->form->getField('certificate'); - $emailField = $this->form->getField('email'); - - if ($fileField->isFilled(Language::err('FieldIsRequired'))) { - $fileField->isAllowedExtension(['p12'], Language::err('P12Only')); - } - $emailField->isFilled(Language::err('FieldIsRequired')); - $emailField->isEmail(Language::err('EmailIsInvalid')); - - return $this->form->isCorrect(); - } -} diff --git a/src/Backend/Modules/Analytics/Form/SettingsStepProfileTypeInterface.php b/src/Backend/Modules/Analytics/Form/SettingsStepProfileTypeInterface.php deleted file mode 100644 index 4d67fa6ef7..0000000000 --- a/src/Backend/Modules/Analytics/Form/SettingsStepProfileTypeInterface.php +++ /dev/null @@ -1,71 +0,0 @@ -form = new Form($name); - - $this->build(); - } - - public function parse(TwigTemplate $template): void - { - $this->form->parse($template); - } - - public function handle(): bool - { - $this->form->cleanupFields(); - - if (!$this->form->isSubmitted() || !$this->isValid()) { - return false; - } - - $this->settings->set( - 'Analytics', - 'profile', - $this->form->getField('profile')->getValue() - ); - - return true; - } - - private function build(): void - { - $profiles = $this->googleServiceAnalytics->management_profiles->listManagementProfiles( - $this->settings->get('Analytics', 'account'), - $this->settings->get('Analytics', 'web_property_id') - ); - - $profilesForDropDown = []; - foreach ($profiles->getItems() as $property) { - $profilesForDropDown[$property->getId()] = $property->getName(); - } - $this->form->addDropdown('profile', $profilesForDropDown); - } - - private function isValid(): bool - { - $this->form->getField('profile')->isFilled(Language::err('FieldIsRequired')); - - return $this->form->isCorrect(); - } -} diff --git a/src/Backend/Modules/Analytics/Form/SettingsStepTypeInterface.php b/src/Backend/Modules/Analytics/Form/SettingsStepTypeInterface.php deleted file mode 100644 index 4c2b31aab4..0000000000 --- a/src/Backend/Modules/Analytics/Form/SettingsStepTypeInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -form = new Form($name); - - $this->build(); - } - - public function parse(TwigTemplate $template): void - { - $this->form->parse($template); - } - - public function handle(): bool - { - $this->form->cleanupFields(); - - if (!$this->form->isSubmitted() || !$this->isValid()) { - return false; - } - - $this->settings->set( - 'Analytics', - 'web_property_id', - $this->form->getField('web_property_id')->getValue() - ); - - return true; - } - - private function build(): void - { - $properties = $this->googleServiceAnalytics->management_webproperties->listManagementWebproperties( - $this->settings->get('Analytics', 'account') - ); - - $propertiesForDropDown = []; - foreach ($properties->getItems() as $property) { - $propertiesForDropDown[$property->getId()] = $property->getName(); - } - $this->form->addDropdown('web_property_id', $propertiesForDropDown); - } - - private function isValid(): bool - { - $this->form->getField('web_property_id')->isFilled(Language::err('FieldIsRequired')); - - return $this->form->isCorrect(); - } -} diff --git a/src/Backend/Modules/Analytics/Form/SettingsType.php b/src/Backend/Modules/Analytics/Form/SettingsType.php deleted file mode 100644 index ea6014e25a..0000000000 --- a/src/Backend/Modules/Analytics/Form/SettingsType.php +++ /dev/null @@ -1,67 +0,0 @@ -get('Analytics', 'certificate') === null) { - $this->form = new SettingsStepAuthConfigFileTypeInterface($name, $settings); - - return; - } - - // we are authenticated! Let's see which account the user wants to use - if ($settings->get('Analytics', 'account') === null) { - $this->form = new SettingsStepAccountTypeInterface($name, $settings, $googleServiceAnalytics); - - return; - } - - // we have an account, but don't know which property to track - if ($settings->get('Analytics', 'web_property_id') === null) { - $this->form = new SettingsStepWebPropertyTypeInterface($name, $settings, $googleServiceAnalytics); - - return; - } - - // we have an account, but don't know which property to track - if ($settings->get('Analytics', 'profile') === null) { - $this->form = new SettingsStepProfileTypeInterface($name, $settings, $googleServiceAnalytics); - - return; - } - - $this->form = new Form($name); - } - - public function parse(TwigTemplate $template): void - { - $this->form->parse($template); - } - - public function handle(): bool - { - if ($this->form instanceof Form) { - return false; - } - - return $this->form->handle(); - } -} diff --git a/src/Backend/Modules/Analytics/GoogleClient/ClientFactory.php b/src/Backend/Modules/Analytics/GoogleClient/ClientFactory.php deleted file mode 100644 index 239ba10cb5..0000000000 --- a/src/Backend/Modules/Analytics/GoogleClient/ClientFactory.php +++ /dev/null @@ -1,47 +0,0 @@ -setClassConfig(Google_Cache_File::class, ['directory' => $this->cacheDir]); - $client = new Google_Client($config); - - // set assertion credentials - $client->setAssertionCredentials( - new Google_Auth_AssertionCredentials( - $this->settings->get('Analytics', 'email'), - ['https://www.googleapis.com/auth/analytics.readonly'], - base64_decode((string) $this->settings->get('Analytics', 'certificate')) - ) - ); - - $client->setAccessType('offline_access'); - - return $client; - } - - public function createAnalyticsService(): Google_Service_Analytics - { - return new Google_Service_Analytics($this->createClient()); - } -} diff --git a/src/Backend/Modules/Analytics/GoogleClient/Connector.php b/src/Backend/Modules/Analytics/GoogleClient/Connector.php deleted file mode 100644 index e57cf49565..0000000000 --- a/src/Backend/Modules/Analytics/GoogleClient/Connector.php +++ /dev/null @@ -1,336 +0,0 @@ -getData($startDate, $endDate); - - return $results['metrics']['ga:pageviews']; - } - - /** - * Returns the amount of visitors in a period - * - * @param int $startDate - * @param int $endDate - * - * @return int - */ - public function getVisitors(int $startDate, int $endDate): int - { - $results = $this->getData($startDate, $endDate); - - return $results['metrics']['ga:users']; - } - - /** - * Returns the amount of pages per visit in a period - * - * @param int $startDate - * @param int $endDate - * - * @return float - */ - public function getPagesPerVisit(int $startDate, int $endDate): float - { - $results = $this->getData($startDate, $endDate); - - return $results['metrics']['ga:pageviewsPerSession']; - } - - /** - * Returns the average time on the site in a certain period - * - * @param int $startDate - * @param int $endDate - * - * @return float - */ - public function getTimeOnSite(int $startDate, int $endDate): float - { - $results = $this->getData($startDate, $endDate); - - return $results['metrics']['ga:avgSessionDuration']; - } - - /** - * Returns the percentage of new sessions in a certain period - * - * @param int $startDate - * @param int $endDate - * - * @return float - */ - public function getNewSessionsPercentage(int $startDate, int $endDate): float - { - $results = $this->getData($startDate, $endDate); - - return $results['metrics']['ga:percentNewSessions']; - } - - /** - * Returns the bounce rate in a certain period - * - * @param int $startDate - * @param int $endDate - * - * @return float - */ - public function getBounceRate(int $startDate, int $endDate): float - { - $results = $this->getData($startDate, $endDate); - - return $results['metrics']['ga:bounceRate']; - } - - /** - * Returns the visitors graph data - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - public function getVisitorsGraphData(int $startDate, int $endDate): array - { - $results = $this->getData($startDate, $endDate); - - return $results['visitGraphData']; - } - - /** - * Returns the source graph data - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - public function getSourceGraphData(int $startDate, int $endDate): array - { - $results = $this->getData($startDate, $endDate); - - return $results['sourceGraphData']; - } - - /** - * Returns the source graph data - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - public function getMostVisitedPagesData(int $startDate, int $endDate): array - { - $results = $this->getData($startDate, $endDate); - - return $results['pageViews']; - } - - /** - * Fetches all the needed data and caches it in our statistics array - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - private function getData(int $startDate, int $endDate): array - { - $dateRange = $startDate . '-' . $endDate; - - $item = $this->cache->getItem('analytics-' . $dateRange); - if ($item->isHit()) { - return $item->get(); - } - - $data = [ - 'metrics' => $this->getMetrics($startDate, $endDate), - 'visitGraphData' => $this->collectVisitGraphData($startDate, $endDate), - 'pageViews' => $this->collectMostVisitedPagesData($startDate, $endDate), - 'sourceGraphData' => $this->collectSourceGraphData($startDate, $endDate), - ]; - - $item->set($data); - $this->cache->save($item); - - return $data; - } - - /** - * Fetches some metrics for a certain date range - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - private function getMetrics(int $startDate, int $endDate): array - { - return $this->getAnalyticsData( - $startDate, - $endDate, - 'ga:pageviews,ga:users,ga:pageviewsPerSession,ga:avgSessionDuration,ga:percentNewSessions,ga:bounceRate' - )->getTotalsForAllResults(); - } - - /** - * Fetches the data needed to build the visitors graph for a date range - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - private function collectVisitGraphData(int $startDate, int $endDate): array - { - $visitGraphData = $this->getAnalyticsData( - $startDate, - $endDate, - 'ga:pageviews,ga:users', - [ - 'dimensions' => 'ga:date', - 'sort' => 'ga:date', - ] - ); - - // make sure our column headers are the metric names, not just numbers - $namedRows = []; - foreach ((array) $visitGraphData->getRows() as $dataRow) { - $namedRow = []; - foreach ($dataRow as $key => $value) { - $headerName = $visitGraphData->getColumnHeaders()[$key]['name']; - - // convert the date to a timestamp - if ($headerName === 'ga:date') { - $value = \DateTime::createFromFormat('Ymd H:i:s', $value . ' 00:00:00')->format('U'); - } - $namedRow[str_replace(':', '_', $headerName)] = $value; - } - $namedRows[] = $namedRow; - } - - return $namedRows; - } - - /** - * Fetches the data needed to build the source graph for a date range - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - private function collectSourceGraphData(int $startDate, int $endDate): array - { - $sourceGraphData = $this->getAnalyticsData( - $startDate, - $endDate, - 'ga:pageviews', - [ - 'dimensions' => 'ga:medium', - 'sort' => '-ga:pageviews', - ] - ); - - // make sure our column headers are the metric names, not just numbers - $namedRows = []; - foreach ((array) $sourceGraphData->getRows() as $dataRow) { - $namedRow = []; - foreach ($dataRow as $key => $value) { - $headerName = $sourceGraphData->getColumnHeaders()[$key]['name']; - $namedRow[str_replace(':', '_', $headerName)] = $value; - } - $namedRows[] = $namedRow; - } - - return $namedRows; - } - - /** - * Fetches the data needed to build the list with most visited pages - * - * @param int $startDate - * @param int $endDate - * - * @return array - */ - private function collectMostVisitedPagesData(int $startDate, int $endDate): array - { - $sourceGraphData = $this->getAnalyticsData( - $startDate, - $endDate, - 'ga:pageviews', - [ - 'dimensions' => 'ga:pagePath', - 'sort' => '-ga:pageviews', - 'max-results' => 20, - ] - ); - - // make sure our column headers are the metric names, not just numbers - $namedRows = []; - foreach ((array) $sourceGraphData->getRows() as $dataRow) { - $namedRow = []; - foreach ($dataRow as $key => $value) { - $headerName = $sourceGraphData->getColumnHeaders()[$key]['name']; - $namedRow[str_replace(':', '_', $headerName)] = $value; - } - $namedRows[] = $namedRow; - } - - return $namedRows; - } - - /** - * Returns Analytics data for our coupled profile - * - * @param int $startDate - * @param int $endDate - * @param string $metrics A comma-separated list of Analytics metrics. - * @param array $optParams Optional parameters. - * - * @return Google_Service_Analytics_GaData - */ - private function getAnalyticsData( - int $startDate, - int $endDate, - string $metrics, - array $optParams = [] - ): Google_Service_Analytics_GaData { - return $this->analytics->data_ga->get( - 'ga:' . $this->settings->get('Analytics', 'profile'), - date('Y-m-d', $startDate), - date('Y-m-d', $endDate), - $metrics, - $optParams - ); - } -} diff --git a/src/Backend/Modules/Analytics/Installer/Data/locale.xml b/src/Backend/Modules/Analytics/Installer/Data/locale.xml deleted file mode 100644 index aa59c62fc8..0000000000 --- a/src/Backend/Modules/Analytics/Installer/Data/locale.xml +++ /dev/null @@ -1,313 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Hoe verkrijg je je secret file? -
-

De Analytics API inschakelen

-

-

    -
  1. Ga naar de Google Developers Console.
  2. -
  3. Zorg dat je aangemeld bent met een Google account die toegang heeft op de gewenste analytics account.
  4. -
  5. Kies een project in de header of maak een nieuw aan.
  6. -
  7. Klik op Bibliotheek in de zijbalk.
  8. -
  9. Ga naar de Analytics API door er op te klikken in de Andere populaire API's categorie of door het te typen in de zoekbalk.
  10. -
  11. Als je de API nog niet geactiveerd hebt kan je dit doen door onder de header op INSCHAKELEN te klikken.
  12. -
-

-

Toegangsgegevens aanmaken voor Fork CMS.

-

-

    -
  1. Kies in de zijbalk aan de linkerkant Inloggegevens.
  2. -
  3. Klik op Inloggegevens maken en kies Serviceaccountsleutel in de dropdown.
  4. -
  5. Maak een nieuw serviceaccount aan met de rol Project - Editor en P12 als type sleutel.
  6. -
  7. Download na het opslaan het gegenereerde certificaat (p12 file).
  8. -
  9. Ga terug naar de Inloggegevens pagina en klik op Serviceaccounts beheren.
  10. -
  11. Kopieer de Serviceaccount-ID van de net aangemaakte account. Het zou er ongeveer als volgt moeten uitzien name@spheric-passkey-123456.iam.gserviceaccount.com
  12. -
  13. Log in in Google Analytics, ga naar het beheerder onderdeel en voeg het gegenereerde e-mail adres toe bij de gewenste property en geef deze "lezen en analyseren" rechten.
  14. -
  15. Haal een kop koffie, en kom daarna terug. Het kan even duren voor de koppeling tot stand is gekomen.
  16. -
-

]]>
- How to get your secret file? -
-

Enable the Analytics API

-

-

    -
  1. Go to the Google Developers Console.
  2. -
  3. Make sure you're logged in with a Google account that has access to the wanted Analytics account.
  4. -
  5. Select a project in the header, or create a new one.
  6. -
  7. Click on Library in the sidebar on the left.
  8. -
  9. Go to the Analytics API page by clicking on it in the Other popular API's category or typing it in the search bar.
  10. -
  11. You can enable the API if you haven't done that yet by clicking on ENABLE API underneath the header.
  12. -
-

-

Creating credentials for Fork CMS.

-

-

    -
  1. In the sidebar on the left, select Credentials.
  2. -
  3. Click on Create credentials and select Service account key in the dropdown.
  4. -
  5. Create a new service account with the role Project - Editor and P12 as Key type.
  6. -
  7. Download the generated certificate (.p12 file).
  8. -
  9. Go back to the Credentials page and click on Manage service accounts
  10. -
  11. Copy the Service account ID of the newly created account. It should look something like name@spheric-passkey-123456.iam.gserviceaccount.com
  12. -
  13. Login to analytics, go to admin page and add the generated e-mail adress to the prefered property with "read and analyze" rights.
  14. -
  15. Grab a cup of coffee, and come back to Fork in some minutes. It can take some time before the coupling is fully done.
  16. -
-

]]>
-
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
-
diff --git a/src/Backend/Modules/Analytics/Installer/Installer.php b/src/Backend/Modules/Analytics/Installer/Installer.php deleted file mode 100644 index 65d94d77f8..0000000000 --- a/src/Backend/Modules/Analytics/Installer/Installer.php +++ /dev/null @@ -1,47 +0,0 @@ -addModule('Analytics'); - $this->importLocale(__DIR__ . '/Data/locale.xml'); - $this->configureBackendNavigation(); - $this->configureBackendRights(); - $this->configureBackendWidgets(); - } - - private function configureBackendNavigation(): void - { - // Set navigation for "Modules" - $navigationMarketingId = $this->setNavigation(null, 'Marketing', 'analytics/index', null, 4); - $this->setNavigation($navigationMarketingId, 'Analytics', 'analytics/index'); - - // Set navigation for "Settings" - $navigationSettingsId = $this->setNavigation(null, 'Settings'); - $navigationModulesId = $this->setNavigation($navigationSettingsId, 'Modules'); - $this->setNavigation($navigationModulesId, $this->getModule(), 'analytics/settings'); - } - - private function configureBackendRights(): void - { - $this->setModuleRights(1, $this->getModule()); - - $this->setActionRights(1, $this->getModule(), 'Index'); - $this->setActionRights(1, $this->getModule(), 'Settings'); - $this->setActionRights(1, $this->getModule(), 'Reset'); - } - - private function configureBackendWidgets(): void - { - $this->insertDashboardWidget('Analytics', 'RecentVisits'); - $this->insertDashboardWidget('Analytics', 'TraficSources'); - } -} diff --git a/src/Backend/Modules/Analytics/Js/Analytics.js b/src/Backend/Modules/Analytics/Js/Analytics.js deleted file mode 100644 index f72590d7ba..0000000000 --- a/src/Backend/Modules/Analytics/Js/Analytics.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Interaction for the analytics module - */ -/* global Highcharts */ -jsBackend.analytics = { - $chartPieChart: null, - $chartDoubleMetricPerDay: null -} - -jsBackend.analytics.charts = { - init: function () { - jsBackend.analytics.$chartPieChart = $('#chartPieChart') - jsBackend.analytics.$chartDoubleMetricPerDay = $('#chartDoubleMetricPerDay') - - if (jsBackend.analytics.$chartPieChart.length > 0 || jsBackend.analytics.$chartDoubleMetricPerDay.length > 0) { - Highcharts.setOptions({ - colors: ['#2f77d1', '#021b45', '#ED561B', '#EDEF00', '#24CBE5', '#64E572', '#FF9655'], - title: {text: ''}, - legend: { - layout: 'vertical', - borderWidth: 0, - shadow: false, - symbolPadding: 12, - symbolWidth: 10, - itemStyle: {cursor: 'pointer', color: '#000', lineHeight: '18px'}, - itemHoverStyle: {color: '#666'} - } - }) - } - - jsBackend.analytics.chartPieChart.init() - jsBackend.analytics.chartDoubleMetricPerDay.init() - } -} - -jsBackend.analytics.chartPieChart = { - chart: '', - - init: function () { - if (jsBackend.analytics.$chartPieChart.length > 0) { jsBackend.analytics.chartPieChart.create() } - }, - - // add new chart - create: function () { - // variables - var $pieChartValues = $('#dataChartPieChart ul.data li') - var pieChartData = [] - - $pieChartValues.each(function () { - // variables - var $this = $(this) - - pieChartData.push({ - name: $this.children('span.label').html(), - y: parseInt($this.children('span.value').html()), - percentage: parseInt($this.children('span.percentage').html()) - }) - }) - - var containerWidth = jsBackend.analytics.$chartPieChart.width() - - jsBackend.analytics.chartPieChart.chart = new Highcharts.Chart({ - chart: { - renderTo: 'chartPieChart', - height: 200, - width: containerWidth, - margin: [0, 160, 0, 0], - backgroundColor: 'transparent' - }, - credits: {enabled: false}, - plotArea: {shadow: null, borderWidth: null, backgroundColor: null}, - tooltip: { - formatter: function () { - var percentage = String(this.point.percentage) - return '' + this.point.name + ': ' + this.y + ' (' + percentage.substring(0, $.inArray('.', percentage) + 3) + '%)' - }, - borderWidth: 2, - shadow: false - }, - plotOptions: { - pie: { - allowPointSelect: true, - dataLabels: { - enabled: false - }, - showInLegend: true - } - }, - legend: {align: 'right'}, - series: [{type: 'pie', data: pieChartData}] - }) - }, - - // destroy chart - destroy: function () { - jsBackend.analytics.chartPieChart.chart.destroy() - } -} - -jsBackend.analytics.chartDoubleMetricPerDay = { - chart: '', - - init: function () { - if (jsBackend.analytics.$chartDoubleMetricPerDay.length > 0) { jsBackend.analytics.chartDoubleMetricPerDay.create() } - }, - - // add new chart - create: function () { - var xAxisItems = $('#dataChartDoubleMetricPerDay ul.series li.serie:first-child ul.data li') - var xAxisValues = [] - var xAxisCategories = [] - var counter = 0 - var interval = Math.ceil(xAxisItems.length / 10) - - xAxisItems.each(function () { - xAxisValues.push($(this).children('span.fulldate').html()) - var text = $(this).children('span.date').html() - if (xAxisItems.length > 10 && counter % interval > 0) text = ' ' - xAxisCategories.push(text) - counter++ - }) - - var maxValue = 0 - var metric1Name = $('#dataChartDoubleMetricPerDay ul.series li#metric1serie span.name').html() - var metric1Values = $('#dataChartDoubleMetricPerDay ul.series li#metric1serie span.value') - var metric1Data = [] - - metric1Values.each(function () { - metric1Data.push(parseInt($(this).html())) - if (parseInt($(this).html()) > maxValue) { - maxValue = parseInt($(this).html()) - } - }) - - var metric2Name = $('#dataChartDoubleMetricPerDay ul.series li#metric2serie span.name').html() - var metric2Values = $('#dataChartDoubleMetricPerDay ul.series li#metric2serie span.value') - var metric2Data = [] - - metric2Values.each(function () { - metric2Data.push(parseInt($(this).html())) - if (parseInt($(this).html()) > maxValue) { - maxValue = parseInt($(this).html()) - } - }) - - var tickInterval = Math.ceil(maxValue / 5) - - var containerWidth = $('#chartDoubleMetricPerDay').width() - - jsBackend.analytics.chartDoubleMetricPerDay.chart = new Highcharts.Chart({ - chart: { - renderTo: 'chartDoubleMetricPerDay', - height: 200, - width: containerWidth, - margin: [60, 0, 30, 40], - defaultSeriesType: 'line', - backgroundColor: 'transparent' - }, - xAxis: {lineColor: '#CCC', lineWidth: 1, categories: xAxisCategories, color: '#000'}, - yAxis: {min: 0, max: maxValue, tickInterval: tickInterval, title: {text: ''}}, - credits: {enabled: false}, - tooltip: {formatter: function () { return '' + this.series.name + '
' + xAxisValues[this.point.x] + ': ' + this.y }}, - plotOptions: { - line: { - marker: { - enabled: false, - states: {hover: {enabled: true, symbol: 'circle', radius: 5, lineWidth: 1}} - } - }, - area: { - marker: { - enabled: false, - states: {hover: {enabled: true, symbol: 'circle', radius: 5, lineWidth: 1}} - } - }, - column: {pointPadding: 0.2, borderWidth: 0}, - series: {fillOpacity: 0.3} - }, - series: [{name: metric1Name, data: metric1Data, type: 'area'}, {name: metric2Name, data: metric2Data}], - legend: {layout: 'horizontal', verticalAlign: 'top'} - }) - }, - - // destroy chart - destroy: function () { - jsBackend.analytics.chartDoubleMetricPerDay.chart.destroy() - } -} - -$(jsBackend.analytics.charts.init) diff --git a/src/Backend/Modules/Analytics/Layout/Templates/Index.html.twig b/src/Backend/Modules/Analytics/Layout/Templates/Index.html.twig deleted file mode 100644 index 11d4b6e290..0000000000 --- a/src/Backend/Modules/Analytics/Layout/Templates/Index.html.twig +++ /dev/null @@ -1,138 +0,0 @@ -{% extends 'Layout/Templates/base.html.twig' %} - -{% block actionbar %} - -{% endblock %} - -{% block content %} -
-
-

{{ 'lbl.Statistics'|trans|ucfirst }} {{ 'lbl.From'|trans }} {{ startTimestamp|date('m/d/Y') }} {{ 'lbl.Till'|trans }} {{ endTimestamp|date('m/d/Y') }}

-
-
-
- {% form date_range %} -
-
- - {% form_field start_date %} - {% form_field_error start_date %} -
-
- - {% form_field end_date %} - {% form_field_error end_date %} -
-
- -
-
- {% endform %} -
- -
-
-
-

{{ page_views }} {{ 'lbl.Pageviews'|trans|ucfirst }}

-

{{ visitors }} {{ 'lbl.Visitors'|trans|ucfirst }}

-
-
-

{{ pages_per_visit|formatfloat }} {{ 'lbl.PagesPerVisit'|trans|ucfirst }}

-

{{ time_on_site|formattime }} {{ 'lbl.AverageTimeOnSite'|trans|ucfirst }}

-
-
-

- {{ new_sessions_percentage|formatfloat }}% {{ 'lbl.NewVisitsPercentage'|trans|ucfirst }} -

-

{{ bounce_rate|formatfloat }}% {{ 'lbl.BounceRate'|trans|ucfirst }}

-
-
-
-
-
-
-
-
-
-
-

{{ 'lbl.RecentVisits'|trans|ucfirst }}

-
-
- {% if visitors_graph_data %} - -
 
- {% endif %} -
-
-
-
-
-
-

{{ 'lbl.PageviewsByTrafficSources'|trans|ucfirst }}

-
-
- {% if source_graph_data %} - -
 
- {% endif %} -
-
-
-
-
- -
-
-
-
-
-

{{ 'lbl.MostViewedPages'|trans|ucfirst }}

-
-
-
- {{ dataGridMostViewedPages|raw }} -
-
-
-
-
-
-{% endblock %} diff --git a/src/Backend/Modules/Analytics/Layout/Templates/Settings.html.twig b/src/Backend/Modules/Analytics/Layout/Templates/Settings.html.twig deleted file mode 100644 index ba5c5932e4..0000000000 --- a/src/Backend/Modules/Analytics/Layout/Templates/Settings.html.twig +++ /dev/null @@ -1,132 +0,0 @@ -{% extends 'Layout/Templates/base.html.twig' %} -{% import "Layout/Templates/macros.html.twig" as macro %} - -{% block actionbar %} - -{% endblock %} - -{% block content %} - {% if noAccounts %} -
-
- -
-
- {% endif %} - {% form settings %} - {% if fileCertificate %} -
-
-
-
-

- {{ 'lbl.Certificate'|trans|ucfirst }} -

-
-
-
-

- {{ 'msg.CertificateHelp'|trans|raw }} -

- {% form_field certificate %} {% form_field_error certificate %} - - {% form_field email %} {% form_field_error email %} -
-
-
-
-
- {% endif %} - {% if ddmAccount %} -
-
-
-
-

- {{ 'lbl.ChooseThisAccount'|trans|ucfirst }} -

-
-
-
- {% form_field account %} -
-
-
-
-
- {% endif %} - {% if ddmWebPropertyId %} -
-
-
-
-

- {{ 'lbl.ChooseWebsiteProfile'|trans|ucfirst }} -

-
-
-
- {% form_field web_property_id %} -
-
-
-
-
- {% endif %} - {% if web_property_id %} -
-
-
-
-

- {{ 'lbl.LinkedProfile'|trans|ucfirst }} -

-
-
-
- {{ web_property_id }}{% if profile %}: ga:profile{% endif %} -
-
-
-
-
- {% endif %} - {% if ddmProfile %} -
-
-
-
-

- {{ 'lbl.ChooseWebsiteProfile'|trans|ucfirst }} -

-
-
-
- {% form_field profile %} -
-
-
-
-
- {% endif %} - -
-
-
- {% if isAllowedAction('Reset') and fileCertificate is not defined %} - - {% endif %} - {% if not profile and (noAccounts == false or noAccounts is not defined) %} -
- {{ macro.buttonIcon('', 'floppy-o', 'lbl.Save'|trans|ucfirst, 'btn-primary', {"id":"save", "type":"submit", "name":"save"}) }} -
- {% endif %} -
-
-
- {% endform %} -{% endblock %} diff --git a/src/Backend/Modules/Analytics/Layout/Widgets/RecentVisits.html.twig b/src/Backend/Modules/Analytics/Layout/Widgets/RecentVisits.html.twig deleted file mode 100644 index 2bc963e5bb..0000000000 --- a/src/Backend/Modules/Analytics/Layout/Widgets/RecentVisits.html.twig +++ /dev/null @@ -1,48 +0,0 @@ -{% if visitors_graph_data %} -
-
-

{{ 'lbl.RecentVisits'|trans|ucfirst }}

-
-
-
- -
 
-
-
- -
-{% endif %} diff --git a/src/Backend/Modules/Analytics/Layout/Widgets/TraficSources.html.twig b/src/Backend/Modules/Analytics/Layout/Widgets/TraficSources.html.twig deleted file mode 100644 index dfec71399c..0000000000 --- a/src/Backend/Modules/Analytics/Layout/Widgets/TraficSources.html.twig +++ /dev/null @@ -1,26 +0,0 @@ -{% if source_graph_data %} -
- -
-
- -
 
-
-
- -
-{% endif %} diff --git a/src/Backend/Modules/Analytics/Resources/config/services.yml b/src/Backend/Modules/Analytics/Resources/config/services.yml deleted file mode 100644 index 98512e2dcd..0000000000 --- a/src/Backend/Modules/Analytics/Resources/config/services.yml +++ /dev/null @@ -1,23 +0,0 @@ -services: - analytics.client_factory: - class: Backend\Modules\Analytics\GoogleClient\ClientFactory - arguments: - - "@fork.settings" - - "%kernel.cache_dir%" - - analytics.google_analytics_service: - class: Google_Service_Analytics - public: true - factory: ["@analytics.client_factory",createAnalyticsService] - - analytics.google_client: - class: Google_Client - factory: ["@analytics.client_factory",createClient] - - analytics.connector: - class: Backend\Modules\Analytics\GoogleClient\Connector - public: true - arguments: - - "@analytics.google_analytics_service" - - "@cache.pool" - - "@fork.settings" diff --git a/src/Backend/Modules/Analytics/Tests/Actions/IndexTest.php b/src/Backend/Modules/Analytics/Tests/Actions/IndexTest.php deleted file mode 100644 index fc9609821d..0000000000 --- a/src/Backend/Modules/Analytics/Tests/Actions/IndexTest.php +++ /dev/null @@ -1,25 +0,0 @@ -login($client); - - self::assertGetsRedirected( - $client, - '/private/en/analytics/index', - '/private/en/analytics/settings' - ); - } -} diff --git a/src/Backend/Modules/Analytics/Tests/Actions/ResetTest.php b/src/Backend/Modules/Analytics/Tests/Actions/ResetTest.php deleted file mode 100644 index 848e7d708c..0000000000 --- a/src/Backend/Modules/Analytics/Tests/Actions/ResetTest.php +++ /dev/null @@ -1,25 +0,0 @@ -login($client); - - self::assertGetsRedirected( - $client, - '/private/en/analytics/reset', - '/private/en/analytics/settings' - ); - } -} diff --git a/src/Backend/Modules/Analytics/Tests/Actions/SettingsTest.php b/src/Backend/Modules/Analytics/Tests/Actions/SettingsTest.php deleted file mode 100644 index f278277a53..0000000000 --- a/src/Backend/Modules/Analytics/Tests/Actions/SettingsTest.php +++ /dev/null @@ -1,21 +0,0 @@ -login($client); - - self::assertPageLoadedCorrectly($client, '/private/en/analytics/settings', ['How to get your secret file?']); - } -} diff --git a/src/Backend/Modules/Analytics/Tests/GoogleClient/ConnectorTest.php b/src/Backend/Modules/Analytics/Tests/GoogleClient/ConnectorTest.php deleted file mode 100644 index dd085bcc1e..0000000000 --- a/src/Backend/Modules/Analytics/Tests/GoogleClient/ConnectorTest.php +++ /dev/null @@ -1,292 +0,0 @@ -getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - 1, - $connector->getPageViews( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetVisitors(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - 2, - $connector->getVisitors( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetPagesPerVisit(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - 3.14, - $connector->getPagesPerVisit( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetTimeOnSite(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - 1.02, - $connector->getTimeOnSite( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetNewSessionsPercentage(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - 78.23, - $connector->getNewSessionsPercentage( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetBounceRate(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - 23.25, - $connector->getBounceRate( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetVisitorsGraphData(): void - { - ini_set('date.timezone', 'Europe/Brussels'); - - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - [ - [ - 'ga_date' => '1431295200', - 'ga_pageviews' => '0', - 'ga_users' => '0', - ], - [ - 'ga_date' => '1431381600', - 'ga_pageviews' => '1', - 'ga_users' => '1', - ], - ], - $connector->getVisitorsGraphData( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetSourceGraphData(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - [ - [ - 'ga_medium' => '(none)', - 'ga_pageviews' => '8', - ], - [ - 'ga_medium' => 'organic', - 'ga_pageviews' => '6', - ], - ], - $connector->getSourceGraphData( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - public function testGetMostVisitedPagesData(): void - { - $connector = new Connector( - $this->getAnalyticsServiceMock(), - new Pool(new MemoryStore()), - $this->getModulesSettingsMock() - ); - - self::assertEquals( - [ - [ - 'ga_pagePath' => '/en', - 'ga_pageviews' => '15', - ], - [ - 'ga_pagePath' => '/en/blog', - 'ga_pageviews' => '8', - ], - ], - $connector->getMostVisitedPagesData( - strtotime('-1 day', mktime(0, 0, 0)), - mktime(0, 0, 0) - ) - ); - } - - private function getModulesSettingsMock(): MockObject - { - return $this->getMockBuilder(ModulesSettings::class) - ->disableOriginalConstructor() - ->getMock() - ; - } - - private function getAnalyticsServiceMock(): Google_Service_Analytics - { - $analyticsService = new Google_Service_Analytics(new Google_Client()); - - $dataGateway = $this->getMockBuilder('Google_Service_Analytics_DataGa_Resource') - ->disableOriginalConstructor() - ->getMock() - ; - - $metricsReturnMock = $this->getMockBuilder('Google_Service_Analytics_GaData')->getMock(); - $metricsReturnMock - ->method('getTotalsForAllResults') - ->willReturn([ - 'ga:pageviews' => 1, - 'ga:users' => 2, - 'ga:pageviewsPerSession' => 3.14, - 'ga:avgSessionDuration' => 1.02, - 'ga:percentNewSessions' => 78.23, - 'ga:bounceRate' => 23.25, - ]) - ; - - $visitGraphDataMock = $this->getMockBuilder('Google_Service_Analytics_GaData')->getMock(); - $visitGraphDataMock - ->method('getRows') - ->willReturn([ - ['20150511', '0', '0'], - ['20150512', '1', '1'], - ]) - ; - $visitGraphDataMock - ->method('getColumnHeaders') - ->willReturn([ - ['name' => 'ga:date'], - ['name' => 'ga:pageviews'], - ['name' => 'ga:users'], - ]) - ; - - $sourceGraphDataMock = $this->getMockBuilder('Google_Service_Analytics_GaData')->getMock(); - $sourceGraphDataMock - ->method('getRows') - ->willReturn([ - ['(none)', '8'], - ['organic', '6'], - ]) - ; - $sourceGraphDataMock - ->method('getColumnHeaders') - ->willReturn([ - ['name' => 'ga:medium'], - ['name' => 'ga:pageviews'], - ]) - ; - - $pageViewsDataMock = $this->getMockBuilder('Google_Service_Analytics_GaData')->getMock(); - $pageViewsDataMock - ->method('getRows') - ->willReturn([ - ['/en', '15'], - ['/en/blog', '8'], - ]) - ; - $pageViewsDataMock - ->method('getColumnHeaders') - ->willReturn([ - ['name' => 'ga:pagePath'], - ['name' => 'ga:pageviews'], - ]) - ; - - $dataGateway->method('get') - ->will(self::onConsecutiveCalls( - $metricsReturnMock, - $visitGraphDataMock, - $pageViewsDataMock, - $sourceGraphDataMock - )) - ; - - $analyticsService->data_ga = $dataGateway; - - return $analyticsService; - } -} diff --git a/src/Backend/Modules/Analytics/Widgets/RecentVisits.php b/src/Backend/Modules/Analytics/Widgets/RecentVisits.php deleted file mode 100644 index 8b4ff3b721..0000000000 --- a/src/Backend/Modules/Analytics/Widgets/RecentVisits.php +++ /dev/null @@ -1,36 +0,0 @@ -get('analytics.connector'); - - $this->template->assign( - 'visitors_graph_data', - $analytics->getVisitorsGraphData($startDate, $endDate) - ); - - $this->header->addJS('highcharts.js', 'Core', false); - $this->header->addJS('Analytics.js', 'Analytics'); - $this->display(); - } catch (Google_Auth_Exception) { - // do nothing, analyticis is probably not set up yet. - } catch (Google_IO_Exception) { - // do nothing, probably no internet connection. - } - } -} diff --git a/src/Backend/Modules/Analytics/Widgets/TraficSources.php b/src/Backend/Modules/Analytics/Widgets/TraficSources.php deleted file mode 100644 index 314619d8cc..0000000000 --- a/src/Backend/Modules/Analytics/Widgets/TraficSources.php +++ /dev/null @@ -1,36 +0,0 @@ -get('analytics.connector'); - - $this->template->assign( - 'source_graph_data', - $analytics->getSourceGraphData($startDate, $endDate) - ); - - $this->header->addJS('highcharts.js', 'Core', false); - $this->header->addJS('Analytics.js', 'Analytics'); - $this->display(); - } catch (Google_Auth_Exception) { - // do nothing, analyticis is probably not set up yet. - } catch (Google_IO_Exception) { - // do nothing, probably no internet connection. - } - } -} diff --git a/src/Backend/Modules/Analytics/info.xml b/src/Backend/Modules/Analytics/info.xml deleted file mode 100644 index c3d4f80262..0000000000 --- a/src/Backend/Modules/Analytics/info.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - Analytics - 2.0.0 - - 3.9.0 - - - - - - - - - - - diff --git a/src/Backend/Modules/Settings/Actions/Index.php b/src/Backend/Modules/Settings/Actions/Index.php index 3f855c33a5..1254e6b3d4 100644 --- a/src/Backend/Modules/Settings/Actions/Index.php +++ b/src/Backend/Modules/Settings/Actions/Index.php @@ -67,7 +67,7 @@ private function loadForm(): void $googleTrackingAnalyticsTrackingId = $this->get('fork.settings')->get( 'Core', 'google_tracking_google_analytics_tracking_id', - $this->get('fork.settings')->get('Analytics', 'web_property_id', '') + '' ); $this->form->addCheckbox( 'google_tracking_google_analytics_tracking_id_enabled', diff --git a/tests/data/test_db.sql b/tests/data/test_db.sql index 5ccefee07a..4e7b4fd172 100644 --- a/tests/data/test_db.sql +++ b/tests/data/test_db.sql @@ -7,69 +7,6 @@ /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Dump of table analytics_keywords -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `analytics_keywords`; - -CREATE TABLE `analytics_keywords` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `keyword` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `entrances` int(11) NOT NULL, - `date` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - - -# Dump of table analytics_landing_pages -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `analytics_landing_pages`; - -CREATE TABLE `analytics_landing_pages` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `page_path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `entrances` int(11) NOT NULL, - `bounces` int(11) NOT NULL, - `bounce_rate` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `start_date` datetime NOT NULL, - `end_date` datetime NOT NULL, - `updated_on` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - - -# Dump of table analytics_pages -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `analytics_pages`; - -CREATE TABLE `analytics_pages` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `page` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `date_viewed` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - - -# Dump of table analytics_referrers -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `analytics_referrers`; - -CREATE TABLE `analytics_referrers` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `referrer` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - `entrances` int(11) NOT NULL, - `date` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - - # Dump of table backend_navigation # ------------------------------------------------------------ @@ -113,13 +50,6 @@ VALUES (21,9,'Search','search/settings',NULL,3), (22,2,'ContentBlocks','content_blocks/index','a:2:{i:0;s:18:\"content_blocks/add\";i:1;s:19:\"content_blocks/edit\";}',2), (23,2,'Tags','tags/index','a:1:{i:0;s:9:\"tags/edit\";}',3), - (24,0,'Marketing','analytics/index',NULL,4), - (25,24,'Analytics','analytics/index','a:1:{i:0;s:17:\"analytics/loading\";}',1), - (26,25,'Content','analytics/content',NULL,1), - (27,25,'AllPages','analytics/all_pages',NULL,2), - (28,25,'ExitPages','analytics/exit_pages',NULL,3), - (29,25,'LandingPages','analytics/landing_pages','a:3:{i:0;s:26:\"analytics/add_landing_page\";i:1;s:27:\"analytics/edit_landing_page\";i:2;s:21:\"analytics/detail_page\";}',4), - (30,9,'Analytics','analytics/settings',NULL,4), (31,2,'Blog','',NULL,4), (32,31,'Articles','blog/index','a:3:{i:0;s:8:\"blog/add\";i:1;s:9:\"blog/edit\";i:2;s:21:\"blog/import_wordpress\";}',1), (33,31,'Comments','blog/comments','a:1:{i:0;s:17:\"blog/edit_comment\";}',2), @@ -488,22 +418,6 @@ VALUES (55,1,'Tags','Edit',7), (56,1,'Tags','Index',7), (57,1,'Tags','MassAction',7), - (58,1,'Analytics','AddLandingPage',7), - (59,1,'Analytics','AllPages',7), - (60,1,'Analytics','CheckStatus',7), - (61,1,'Analytics','Content',7), - (62,1,'Analytics','DeleteLandingPage',7), - (63,1,'Analytics','DetailPage',7), - (64,1,'Analytics','ExitPages',7), - (65,1,'Analytics','GetTrafficSources',7), - (66,1,'Analytics','Index',7), - (67,1,'Analytics','LandingPages',7), - (68,1,'Analytics','Loading',7), - (69,1,'Analytics','MassLandingPageAction',7), - (70,1,'Analytics','RefreshTrafficSources',7), - (71,1,'Analytics','Settings',7), - (72,1,'Analytics','TrafficSources',7), - (73,1,'Analytics','Visitors',7), (74,1,'Blog','AddCategory',7), (75,1,'Blog','Add',7), (76,1,'Blog','Categories',7), @@ -573,7 +487,6 @@ VALUES (178,2,'Pages','Edit',7), (179,2,'Pages','Settings',7), (180,3,'Users','Edit',7), - (181,1,'Analytics','Reset',7), (182,1,'Extensions','ExportThemeTemplates',7), (183,1,'Location','Settings',7), (184,1,'Mailmotor','Ping',7), @@ -638,7 +551,6 @@ VALUES (8,1,'Search'), (9,1,'ContentBlocks'), (10,1,'Tags'), - (11,1,'Analytics'), (12,1,'Blog'), (13,1,'Faq'), (14,1,'FormBuilder'), @@ -1030,7 +942,6 @@ VALUES (327, 1, 'en', 'Backend', 'Core', 'lbl', 'Amount', 'amount', '2017-08-31 14:28:18'), (328, 1, 'en', 'Backend', 'Core', 'lbl', 'Analyse', 'analyse', '2017-08-31 14:28:18'), (329, 1, 'en', 'Backend', 'Core', 'lbl', 'Analysis', 'analysis', '2017-08-31 14:28:18'), - (330, 1, 'en', 'Backend', 'Core', 'lbl', 'Analytics', 'analytics', '2017-08-31 14:28:18'), (331, 1, 'en', 'Backend', 'Core', 'lbl', 'APIKey', 'API key', '2017-08-31 14:28:18'), (332, 1, 'en', 'Backend', 'Core', 'lbl', 'APIKeys', 'API keys', '2017-08-31 14:28:18'), (333, 1, 'en', 'Backend', 'Core', 'lbl', 'APIURL', 'API URL', '2017-08-31 14:28:18'), @@ -1784,24 +1695,6 @@ VALUES (1083, 1, 'en', 'Backend', 'Tags', 'err', 'NonExisting', 'This tag doesn\'t exist.', '2017-08-31 14:28:22'), (1084, 1, 'en', 'Backend', 'Tags', 'err', 'NoSelection', 'No tags were selected.', '2017-08-31 14:28:22'), (1085, 1, 'en', 'Backend', 'Tags', 'err', 'TagAlreadyExists', 'This tag already exists.', '2017-08-31 14:28:22'), - (1086, 1, 'en', 'Backend', 'Analytics', 'lbl', 'AverageTimeOnSite', 'average time on site', '2017-08-31 14:28:22'), - (1087, 1, 'en', 'Backend', 'Analytics', 'lbl', 'BounceRate', 'bounce rate', '2017-08-31 14:28:22'), - (1088, 1, 'en', 'Backend', 'Analytics', 'lbl', 'ChangePeriod', 'change period', '2017-08-31 14:28:22'), - (1089, 1, 'en', 'Backend', 'Analytics', 'lbl', 'ChooseThisAccount', 'choose this account', '2017-08-31 14:28:22'), - (1090, 1, 'en', 'Backend', 'Analytics', 'lbl', 'ChooseWebsiteProfile', 'Choose an Analytics website profile...', '2017-08-31 14:28:22'), - (1091, 1, 'en', 'Backend', 'Analytics', 'lbl', 'GaPagePath', 'page', '2017-08-31 14:28:22'), - (1092, 1, 'en', 'Backend', 'Analytics', 'lbl', 'GaPageviews', 'pageviews', '2017-08-31 14:28:22'), - (1093, 1, 'en', 'Backend', 'Analytics', 'lbl', 'LinkedProfile', 'linked profile', '2017-08-31 14:28:22'), - (1094, 1, 'en', 'Backend', 'Analytics', 'lbl', 'NewVisitsPercentage', 'new visits percentage', '2017-08-31 14:28:22'), - (1095, 1, 'en', 'Backend', 'Analytics', 'lbl', 'PagesPerVisit', 'pages per visit', '2017-08-31 14:28:22'), - (1096, 1, 'en', 'Backend', 'Analytics', 'lbl', 'Pageviews', 'pageviews', '2017-08-31 14:28:22'), - (1097, 1, 'en', 'Backend', 'Analytics', 'lbl', 'Certificate', 'certificate (.p12 file)', '2017-08-31 14:28:22'), - (1098, 1, 'en', 'Backend', 'Analytics', 'lbl', 'MostViewedPages', 'most viewed pages', '2017-08-31 14:28:22'), - (1099, 1, 'en', 'Backend', 'Analytics', 'lbl', 'Visitors', 'visitors', '2017-08-31 14:28:22'), - (1100, 1, 'en', 'Backend', 'Analytics', 'err', 'P12Only', 'Only p12 files are allowed.', '2017-08-31 14:28:22'), - (1101, 1, 'en', 'Backend', 'Analytics', 'msg', 'CertificateHelp', '\n

How to get your secret file?

\n
\n

Enable the Analytics API

\n

\n

    \n
  1. Go to the Google Developers Console.
  2. \n
  3. Make sure you\'re logged in with a Google account that has access to the wanted Analytics account.
  4. \n
  5. Select a project in the header, or create a new one.
  6. \n
  7. Click on Library in the sidebar on the left.
  8. \n
  9. Go to the Analytics API page by clicking on it in the Other popular API\'s category or typing it in the search bar.
  10. \n
  11. You can enable the API if you haven\'t done that yet by clicking on ENABLE API underneath the header.
  12. \n
\n

\n

Creating credentials for Fork CMS.

\n

\n

    \n
  1. In the sidebar on the left, select Credentials.
  2. \n
  3. Click on Create credentials and select Service account key in the dropdown.
  4. \n
  5. Create a new service account with the role Project - Editor and P12 as Key type.
  6. \n
  7. Download the generated certificate (.p12 file).
  8. \n
  9. Go back to the Credentials page and click on Manage service accounts
  10. \n
  11. Copy the Service account ID of the newly created account. It should look something like name@spheric-passkey-123456.iam.gserviceaccount.com
  12. \n
  13. Login to analytics, go to admin page and add the generated e-mail adress to the prefered property with \"read and analyze\" rights.
  14. \n
  15. Grab a cup of coffee, and come back to Fork in some minutes. It can take some time before the coupling is fully done.
  16. \n
\n

', '2017-08-31 14:28:22'), - (1102, 1, 'en', 'Backend', 'Analytics', 'msg', 'NoAccounts', 'There are no analytics accounts coupled to the given email address. Make sure you added the email address %1$s to the wanted account. It can take a while before the coupling is completed.', '2017-08-31 14:28:22'), - (1103, 1, 'en', 'Backend', 'Analytics', 'msg', 'RemoveAccountLink', 'Remove the link with your Google account', '2017-08-31 14:28:22'), (1104, 1, 'en', 'Backend', 'Core', 'lbl', 'PageviewsByTrafficSources', 'pageviews per traffic source', '2017-08-31 14:28:22'), (1105, 1, 'en', 'Backend', 'Blog', 'lbl', 'Add', 'add article', '2017-08-31 14:28:23'), (1106, 1, 'en', 'Backend', 'Blog', 'lbl', 'WordpressFilter', 'filter', '2017-08-31 14:28:23'), @@ -2373,7 +2266,6 @@ VALUES ('Search','2015-02-23 19:48:53'), ('ContentBlocks','2015-02-23 19:48:53'), ('Tags','2015-02-23 19:48:53'), - ('Analytics','2015-02-23 19:48:53'), ('Blog','2015-02-23 19:48:53'), ('Faq','2015-02-23 19:48:53'), ('FormBuilder','2015-02-23 19:48:53'),