JackHaK / TMF

0 stars 0 forks source link

Spike Google Analytics integration #2

Open PeteHaK opened 6 years ago

seanthepottingshed commented 6 years ago

EXAMPLE CLASS FOR CALLING GOOGLE ANALYTICS IN ORDER TO RETRIEVE COURSE PAGE VIEW COUNT

The below is an example class taken from another website where similar functionality was required.

The following parameters would need to be stored in ENV:

Google API Client can be installed via composer:

composer require google/apiclient
<?php

namespace HumbleAndKind\Courses\Console;

use Google_Client;
use Google_Service_Analytics;
use HumbleAndKind\Courses\Models\Course;
use Illuminate\Console\Command;

/**
 * View Count.
 */
class ViewCount extends Command
{
    /**
     * Name.
     *
     * @var string
     */
    protected $name = 'course:view-count';

    /**
     * Description.
     *
     * @var string
     */
    protected $description = 'Retrieve course view count from Google Analytics API.';

    /**
     * Handle.
     *
     * @return void
     */
    public function handle()
    {
        $this->info('Fetching course view counts from Google Analytics API');
        $courses = Course::exampleScopeForFiltering()->get();
        if (!empty($courses)) {
            $progressBar            = $this->output->createProgressBar(count($courses));
            $googleServiceAnalytics = $this->getGoogleServiceAnalytics();
            $profileId              = 'ga:' . env('GOOGLE_CLIENT_PROFILE_ID');
            foreach ($courses as $count => $course) {
                $this->callGoogleAnalyticsApi($course, $googleServiceAnalytics, $profileId);
                $progressBar->advance();
            }
            $progressBar->finish();
            $this->info("\n");
        } else {
            $this->error('No courses matching scope found.');
        }
    }

    /**
     * Call Google Analytics API.
     *
     * @param  HumbleAndKind\Courses\Models\Course $course
     * @param  Google_Service_Analytics $googleServiceAnalytics
     * @param  string $profileId
     *
     * @return void
     */
    protected function callGoogleAnalyticsApi($course, $googleServiceAnalytics, $profileId)
    {
        $pagePathFilter = $this->getPagePathFilter($course);
        $viewCount      = $googleServiceAnalytics->data_ga->get($profileId, $startDays = '30daysAgo', $endDays = '0daysAgo', 'ga:pageViews', [
            'dimensions' => 'ga:date',
            'filters'    => $pagePathFilter,
        ])->totalsForAllResults['ga:pageViews'];
        $course->view_count = $viewCount;
        $course->save();
    }

    /**
     * Get Google Service Analytics
     *
     * @return Google_Service_Analytics
     */
    protected function getGoogleServiceAnalytics()
    {
        $client = new Google_Client();
        $apiKey = json_decode(env('GOOGLE_CLIENT_API_KEY'), true);
        $client->setApplicationName('Analytics Reporting');
        $client->setAuthConfig($apiKey);
        $client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);
        $googleServiceAnalytics = new Google_Service_Analytics($client);
        return $googleServiceAnalytics;
    }

    /**
     * Get Page Path Filter.
     *
     * @param  HumbleAndKind\Courses\Models\Course $course
     *
     * @return string
     */
    protected function getPagePathFilter($course)
    {
        return env('APP_ENV') === 'production' ? 'ga:pagePath%3D~%5E' . $course->url . '/' : 'ga:pagePath%3D~%5E/courses/';
    }
}

GOOGLE_CLIENT_API_KEY

{
"type": "service_account",
"project_id": "gta-university-centre",
"private_key_id": "aa63b86537759d0ca4149d4e84003f1c468680de",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCob/v1JO+hIYem\nDzA20YCq7+5TREC7xCg6bqhDt8kK/NuEutQn71qku2Molo7s/4h2/IpYkCkVmEz2\nL/CZwRop76JQXfE5rtQMuc0LuCAk8neVMBZcXrcimhPyhmiVzszvAjg2mrkLhfEZ\n+FuPbSh/d+l2oxITJo3peZsDwEcgYHCEaC6Vuo9p1+jwR4g8RCvtOkkk0Na9kvrt\n3MNsZcnnLoKn1PgNQqOZdxaDt6dA09/qyBgeFg3P9/CGl2U3Td+mPxrnAcd4o/DB\niAb2lwsyHyUNLXeTcCKBKNASv5QA9MjPygjsWxqWL8tINEGOkRxWPv3kAL2KLqcb\npmOpfrkJAgMBAAECggEAEtxbR8OHi7Dv+hHIUdMax8lPFAbYAs5/vK9IazDIs9DF\nmfK7r+8W5MxQ2aomPfaNJtm3ehxGZXMk5wpONEFRtzFsqPgj+1QOzY/+nFnVS53U\n8yEr19MJSbgcFLOlQWUjQH4sojyoDNjGOyS6x/AusTtRqqWu7/MIwASMbZqZvE+x\nqW3hkxkX7fBAgXxPUrRqCqF1mQheYak6cqTicqjaUPGgxGjt8xWS741SYQHGajuW\n3tklHBc4S1CGbvvHB2cPy0EM7Ezja45r6YsWrIGyTlO/tI7BFtxdFNXgayxrKyyf\nSh5U0u+92J2bGancAdJbBmYU7Ct68dob2lwTtLjekwKBgQDaYOIkA3GBHYNgZaIS\nTZKQoA+dZR4fduFpeB8AMcG1aOe/3OYGomoMotSVrgiNL9oiXTkoJezXdaEtsXVP\nqWQXvlIiiu7A+AWHLXaGnJXael8AQ91x0C+Gt6uGzsswFrVNhu115QYDEmwTXY9u\nLs0Fk6OrwdFXIKmbjRkAcMKbxwKBgQDFdI8PDghGO/94LCaOt6NCsXWqJPgRv4Mm\nixivlmleyXRY/JWpOS/nqhJc5GZezlQa7G0eSayyMROrY82uQUlFN7HMwly/Ai92\nm+ZgZOAtu/yzu3/uZ0xmymFjHPWd480392/b1zlvntqhSNnTpZeU5MoxxPWt+85Z\nCVSuNn/krwKBgBO5ElOMWBEAOGBZbYTXqrgTLLXbbxgKZZtf9PTQiZ03x06FxeSt\ngIR5pFeMa0tNGhdmcgYVPsnK3u7Ai0bRlq+qScLC54NYIy+tRHot5D7iNHhSqMph\nshkpt30qaiGCu4cv+3xdXeijHk21coHSCkRJrEuT6rNCyO66lJp8lKb7AoGAQzuD\n9qFVieyl+Ro3asL2kR/xq6R43zoxgu870ZXKfR7lQeOHZh51xFDxfbW7ca6Zjq1Q\nHk8BwY7aXrJV9259b1cecFUB1Xv+A0nkMJBIkOoAioZeciO0LQ/eByx2KXPGjbbv\n3JA1G1+gm+g9W0Z4DZe1jSq+aKZjxYda0RL3izsCgYB01YDgO3JWiDXvhN5fIJfj\nYOvww6GjvX263J9RA7MVJYT7Inx/HkKaWSJf0KNssH12jKCp4UrYeoti5IhVxsuB\nStPB3Gv3YmrcRc3pey+H66cWlv4zDM39VFlUAE7JXb23hKEIUp9FVUsGNhmixdSg\nwFudH/HjRyTcoNld12PFiw==\n-----END PRIVATE KEY-----\n",
"client_email": "tps-830@gta-university-centre.iam.gserviceaccount.com",
"client_id": "103583506389540794818",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/tps-830%40gta-university-centre.iam.gserviceaccount.com"
}

GOOGLE_CLIENT_PROFILE_ID

96544455
seanthepottingshed commented 6 years ago

@JackHaK

Apologies for radio silence, I've been developing a large chunk of the non integration tier dependent website so that my colleague can get on with skinning it all.

In the meantime have you had any joy with integrating the above?

PeteHaK commented 6 years ago

Welcome back - we've not looked at it cos we hadn't heard anything from you and wwe were waiting for some direction as to where you wanted to focus next. Jack has now started a new role so things will be a bit less responsive so if you can start queueing up the things you need then I can get them done.

The issue with the Google Analytics integration is that we have no concept of a web page and no URL for the course. We can store the URL and integrate but you need to work out whether you are interested in events or courses. i.e if I'm looking at a course on a particular date is that a different page to looking at the generic course. People are more likely to be looking at Events than Courses. Can you discuss with Josh.

seanthepottingshed commented 6 years ago

@PeteHaK

No worries, totally understand re: Jack's new role. I will start adding more issues here over the course of the next couple of days. There is plenty of other development work to be done on the website whilst they're being queued up.

As regards the concept of Events and Courses I totally agree with you this needs clarification from our end - we only want bookable instances to appear in the website ( for simplicity of presentation to the end user on the website Events and Courses would be referred to as Courses )

With this in mind I'm going to discuss this further with Josh then go through the current site and provide an example of how each of the following should be presented as bookable instances within the Integration Tier:

Getting back to the Google Analytics integration the course URL definition of the new website it will be of the following structure:

I don't see any benefit in including a course sub category in the URL structure, although if this is deemed necessary then it could be included.

As regards Laravel development this can be implemented via a mutator in the Course model as follows:

public function getUrlAttribute()
{
    return '/courses/' . $this->category->slug . '/' . $this->slug . '/' . $this->id;
}

...which would be used to return unique page views for the new Course URL structure when published to production as follows:

/**
 * Get Page Path Filter.
 *
 * @param  HumbleAndKind\Courses\Models\Course $course
 *
 * @return string
 */
protected function getPagePathFilter($course)
{
    return env('APP_ENV') === 'production' ? 'ga:pagePath%3D~%5E' . $course->url . '/' : 'ga:pagePath%3D~%5E/courses/';
}

...but return unique page views for https://www.gta.gg/courses/ in the meantime. I would use the same mutator in the frontend of the website for the generation of sitemap.xml, etc, etc, in order to ensure that all is in sync.