<commit_before><?php namespace Spatie\AnalyticsReports;

use Thujohn\Analytics\Analytics;
use Illuminate\Support\Collection;
use Carbon\Carbon;
use Cache;


/**
 * Retrieve data from Google Analytics
 *
 * Class Analytics
 * @package Spatie\Services\Analytics
 */
class AnalyticsReports {

    /**
     * @var Analytics
     */
    protected $client;
    /**
     * @var string
     */
    protected $siteId;
    /**
     * @var int
     */
    protected $cacheLifeTimeInMinutes;

    /**
     * @param Analytics $client An already authenticated client
     * @param string $siteId Should look something like ga:xxxxxxxxx
     * @param int $cacheLifeTimeInMinutes
     */
    public function __construct(Analytics $client, $siteId = '', $cacheLifeTimeInMinutes = 0)
    {
        $this->client = $client;
        $this->siteId = $siteId;
        $this->cacheLifeTimeInMinutes = $cacheLifeTimeInMinutes ;
    }

    /**
     * Get the amount of visitors and pageviews
     *
     * @param int $numberOfDays
     * @param string $groupBy Possible values: date, yearMonth
     * @return Collection
     */
    public function getVisitorsAndPageViews($numberOfDays = 365, $groupBy = 'date')
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getVisitorsAndPageViewsForPeriod($startDate, $endDate, $groupBy);
    }

    /**
     * Get the amount of visitors and pageviews for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param string $groupBy  Possible values: date, yearMonth
     * @return Collection
     */
    public function getVisitorsAndPageViewsForPeriod($startDate, $endDate, $groupBy = 'date')
    {
        $visitorData = [];
        $answer = $this->performQuery($startDate, $endDate, 'ga:visits,ga:pageviews', ['dimensions'=>'ga:' . $groupBy]);

        foreach($answer->rows as $dateRow)
        {
            $visitorData[] = [$groupBy => Carbon::createFromFormat(($groupBy == 'yearMonth' ? 'Ym' : 'Ymd'), $dateRow[0]), 'visitors' => $dateRow[1], 'pageViews'=> $dateRow[2]];
        }

        return new Collection($visitorData);
    }

    /**
     * Get the top keywords
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getTopKeywords($numberOfDays = 365, $maxResults = 30)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getTopKeyWordsForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the top keywords for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param int $maxResults
     * @return Collection
     */
    public function getTopKeyWordsForPeriod($startDate, $endDate, $maxResults = 30)
    {
        $keywordData = [];

        $answer = $this->performQuery($startDate, $endDate, 'ga:sessions', ['dimensions'=>'ga:keyword', 'sort'=>'-ga:sessions', 'max-results'=> $maxResults, 'filters'=>'ga:keyword!=(not set);ga:keyword!=(not provided)']);
        foreach($answer->rows as $pageRow)
        {
            $keywordData[] = ['keyword' => $pageRow[0], 'sessions'=>$pageRow[1]];
        }

        return new Collection($keywordData);
    }

    /**
     * Get the top referrers
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getTopReferrers($numberOfDays = 365, $maxResults = 20)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getTopReferrersForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the top referrers for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $maxResults
     * @return Collection
     */
    public function getTopReferrersForPeriod($startDate, $endDate, $maxResults)
    {
        $referrerData = [];

        $answer = $this->performQuery($startDate, $endDate, 'ga:pageviews', ['dimensions'=>'ga:fullReferrer', 'sort'=>'-ga:pageviews', 'max-results'=> $maxResults]);
        foreach($answer->rows as $pageRow)
        {
            $referrerData[] = ['url' => $pageRow[0], 'pageViews'=>$pageRow[1]];
        }

        return new Collection($referrerData);
    }


    /**
     * Get the top browsers
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getTopBrowsers($numberOfDays = 365, $maxResults = 6)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getTopBrowsersForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the top browsers for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $maxResults
     * @return Collection
     */
    public function getTopBrowsersForPeriod($startDate, $endDate, $maxResults)
    {
        $browserData = [];
        $answer = $this->performQuery($startDate, $endDate, 'ga:sessions', ['dimensions'=>'ga:browser', 'sort'=>'-ga:sessions']);
        foreach($answer->rows as $browserRow)
        {
            $browserData[] = ['browser' => $browserRow[0], 'sessions'=>$browserRow[1]];
        }

        $browserCollection = new Collection(array_slice($browserData, 0, $maxResults - 1));

        if (count($browserData) > $maxResults)
        {
            $otherBrowsers = new Collection(array_slice($browserData, $maxResults - 1));
            $otherBrowsersCount = array_sum($otherBrowsers->lists('sessions'));

            $browserCollection->put(null, ['browser'=>'other', 'sessions'=> $otherBrowsersCount]);
        }

        return $browserCollection;
    }


    /**
     * Get the most visited pages
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getMostVisitedPages($numberOfDays = 365, $maxResults = 20)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getMostVisitedPagesForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the most visited pages for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param int $maxResults
     * @return Collection
     */
    public function getMostVisitedPagesForPeriod($startDate, $endDate, $maxResults = 20)
    {
        $pagesData = [];

        $answer = $this->performQuery($startDate, $endDate, 'ga:pageviews', ['dimensions'=>'ga:pagePath', 'sort'=>'-ga:pageviews', 'max-results'=> $maxResults]);

        foreach($answer->rows as $pageRow)
        {
            $pagesData[] = ['url' => $pageRow[0], 'pageViews'=>$pageRow[1]];
        }

        return new Collection($pagesData);
    }


    /**
     * Returns the site id (ga:xxxxxxx) for the given url
     *
     * @param $url
     * @throws \Exception
     * @return string
     */
    public function getSiteIdByUrl($url)
    {
        return $this->client->getSiteIdByUrl($url);
    }


    /**
     * Call the query method on the autenthicated client
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $metrics
     * @param array $others
     * @return mixed
     */
    public function performQuery($startDate, $endDate, $metrics, $others = array())
    {
        $cacheName = $this->determineCacheName(func_get_args());

        if ($this->useCache() AND Cache::has($cacheName))
        {
            $answer = Cache::get($cacheName);
        }
        else
        {
            $answer = $this->client->query($this->siteId,  $startDate->format('Y-m-d'), $endDate->format('Y-m-d'), $metrics, $others);
            if ($this->useCache())
            {
                Cache::put($cacheName, $answer, $this->cacheLifeTimeInMinutes);
            }

        }

        return $answer;

    }

    /**
     * Return true if this site is configured to use Google Analytics
     *
     * @return bool
     */
    public function isEnabled()
    {
        return ! $this->siteId == '';
    }

    /**
     * Determine the cache name for the set of query properties given
     *
     * @param array $properties
     * @return string
     */
    private function determineCacheName(array $properties)
    {
        return 'spatie.analyticsReports.' . md5(serialize($properties));
    }

    /**
     * Returns an array with the current date and the date minus the number of days specified
     *
     * @param $numberOfDays
     * @return array
     */
    private function calculateNumberOfDays($numberOfDays)
    {
        $endDate = Carbon::today();
        $startDate = Carbon::today()->subDays($numberOfDays);
        return [$startDate, $endDate];
    }



    /**
     * Determine if request to Google should be cached
     *
     * @return bool
     */
    private function useCache()<commit_msg>Update AnalyticsReports.php<commit_after><?php namespace Spatie\AnalyticsReports;

use Thujohn\Analytics\Analytics;
use Illuminate\Support\Collection;
use Carbon\Carbon;
use Cache;


/**
 * Retrieve data from Google Analytics
 *
 * Class Analytics
 * @package Spatie\Services\Analytics
 */
class AnalyticsReports
{
    /**
     * @var Analytics
     */
    protected $client;
    /**
     * @var string
     */
    protected $siteId;
    /**
     * @var int
     */
    protected $cacheLifeTimeInMinutes;

    /**
     * @param Analytics $client An already authenticated client
     * @param string $siteId Should look something like ga:xxxxxxxxx
     * @param int $cacheLifeTimeInMinutes
     */
    public function __construct(Analytics $client, $siteId = '', $cacheLifeTimeInMinutes = 0)
    {
        $this->client = $client;
        $this->siteId = $siteId;
        $this->cacheLifeTimeInMinutes = $cacheLifeTimeInMinutes;
    }

    /**
     * Get the amount of visitors and pageviews
     *
     * @param int $numberOfDays
     * @param string $groupBy Possible values: date, yearMonth
     * @return Collection
     */
    public function getVisitorsAndPageViews($numberOfDays = 365, $groupBy = 'date')
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getVisitorsAndPageViewsForPeriod($startDate, $endDate, $groupBy);
    }

    /**
     * Get the amount of visitors and pageviews for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param string $groupBy Possible values: date, yearMonth
     * @return Collection
     */
    public function getVisitorsAndPageViewsForPeriod($startDate, $endDate, $groupBy = 'date')
    {
        $visitorData = [];
        $answer = $this->performQuery($startDate, $endDate, 'ga:visits,ga:pageviews', ['dimensions' => 'ga:' . $groupBy]);

        foreach ($answer->rows as $dateRow) {
            $visitorData[] = [$groupBy => Carbon::createFromFormat(($groupBy == 'yearMonth' ? 'Ym' : 'Ymd'), $dateRow[0]), 'visitors' => $dateRow[1], 'pageViews' => $dateRow[2]];
        }

        return new Collection($visitorData);
    }

    /**
     * Get the top keywords
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getTopKeywords($numberOfDays = 365, $maxResults = 30)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getTopKeyWordsForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the top keywords for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param int $maxResults
     * @return Collection
     */
    public function getTopKeyWordsForPeriod($startDate, $endDate, $maxResults = 30)
    {
        $keywordData = [];

        $answer = $this->performQuery($startDate, $endDate, 'ga:sessions', ['dimensions' => 'ga:keyword', 'sort' => '-ga:sessions', 'max-results' => $maxResults, 'filters' => 'ga:keyword!=(not set);ga:keyword!=(not provided)']);

        if (is_null($answer->rows)) {
            return new Collection([]);
        }
        
        foreach ($answer->rows as $pageRow) {
            $keywordData[] = ['keyword' => $pageRow[0], 'sessions' => $pageRow[1]];
        }

        return new Collection($keywordData);
    }

    /**
     * Get the top referrers
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getTopReferrers($numberOfDays = 365, $maxResults = 20)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getTopReferrersForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the top referrers for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $maxResults
     * @return Collection
     */
    public function getTopReferrersForPeriod($startDate, $endDate, $maxResults)
    {
        $referrerData = [];

        $answer = $this->performQuery($startDate, $endDate, 'ga:pageviews', ['dimensions' => 'ga:fullReferrer', 'sort' => '-ga:pageviews', 'max-results' => $maxResults]);

        if (is_null($answer->rows)) {
            return new Collection([]);
        }
        
        foreach ($answer->rows as $pageRow) {
            $referrerData[] = ['url' => $pageRow[0], 'pageViews' => $pageRow[1]];
        }

        return new Collection($referrerData);
    }


    /**
     * Get the top browsers
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getTopBrowsers($numberOfDays = 365, $maxResults = 6)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getTopBrowsersForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the top browsers for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $maxResults
     * @return Collection
     */
    public function getTopBrowsersForPeriod($startDate, $endDate, $maxResults)
    {
        $browserData = [];
        $answer = $this->performQuery($startDate, $endDate, 'ga:sessions', ['dimensions' => 'ga:browser', 'sort' => '-ga:sessions']);

        if (is_null($answer->rows)) {
            return new Collection([]);
        }
        
        foreach ($answer->rows as $browserRow) {
            $browserData[] = ['browser' => $browserRow[0], 'sessions' => $browserRow[1]];
        }

        $browserCollection = new Collection(array_slice($browserData, 0, $maxResults - 1));

        if (count($browserData) > $maxResults) {
            $otherBrowsers = new Collection(array_slice($browserData, $maxResults - 1));
            $otherBrowsersCount = array_sum($otherBrowsers->lists('sessions'));

            $browserCollection->put(null, ['browser' => 'other', 'sessions' => $otherBrowsersCount]);
        }

        return $browserCollection;
    }
    
    /**
     * Get the most visited pages
     *
     * @param int $numberOfDays
     * @param int $maxResults
     * @return Collection
     */
    public function getMostVisitedPages($numberOfDays = 365, $maxResults = 20)
    {
        list($startDate, $endDate) = $this->calculateNumberOfDays($numberOfDays);
        return $this->getMostVisitedPagesForPeriod($startDate, $endDate, $maxResults);
    }

    /**
     * Get the most visited pages for the given period
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param int $maxResults
     * @return Collection
     */
    public function getMostVisitedPagesForPeriod($startDate, $endDate, $maxResults = 20)
    {
        $pagesData = [];

        $answer = $this->performQuery($startDate, $endDate, 'ga:pageviews', ['dimensions' => 'ga:pagePath', 'sort' => '-ga:pageviews', 'max-results' => $maxResults]);


        if (is_null($answer->rows)) {
            return new Collection([]);
        }


        foreach ($answer->rows as $pageRow) {
            $pagesData[] = ['url' => $pageRow[0], 'pageViews' => $pageRow[1]];
        }

        return new Collection($pagesData);
    }


    /**
     * Returns the site id (ga:xxxxxxx) for the given url
     *
     * @param $url
     * @throws \Exception
     * @return string
     */
    public function getSiteIdByUrl($url)
    {
        return $this->client->getSiteIdByUrl($url);
    }


    /**
     * Call the query method on the autenthicated client
     *
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $metrics
     * @param array $others
     * @return mixed
     */
    public function performQuery($startDate, $endDate, $metrics, $others = array())
    {
        $cacheName = $this->determineCacheName(func_get_args());

        if ($this->useCache() AND Cache::has($cacheName)) {
            $answer = Cache::get($cacheName);
        } else {
            $answer = $this->client->query($this->siteId, $startDate->format('Y-m-d'), $endDate->format('Y-m-d'), $metrics, $others);
            if ($this->useCache()) {
                Cache::put($cacheName, $answer, $this->cacheLifeTimeInMinutes);
            }

        }

        return $answer;
    }

    /**
     * Return true if this site is configured to use Google Analytics
     *
     * @return bool
     */
    public function isEnabled()
    {
        return !$this->siteId == '';
    }

    /**
     * Determine the cache name for the set of query properties given
     *
     * @param array $properties
     * @return string
     */
    private function determineCacheName(array $properties)
    {
        return 'spatie.analyticsReports.' . md5(serialize($properties));
    }

    /**
     * Returns an array with the current date and the date minus the number of days specified
     *
     * @param $numberOfDays
     * @return array
     */
    private function calculateNumberOfDays($numberOfDays)
    {
        $endDate = Carbon::today();
        $startDate = Carbon::today()->subDays($numberOfDays);
        return [$startDate, $endDate];
    }


    /**
     * Determine if request to Google should be cached
     *
     * @return bool
     */
    private function useCache()
{'fraction_non_alphanumeric': 0.13959958540177841, 'fraction_numerical': 0.004582401396541378, 'mean_word_length': 2.5623785464438398, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 137, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2939639', 'n_tokens_mistral': 5626, 'n_tokens_neox': 5373, 'n_words': 1242}