AbstractRelatedSearch   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 5
dl 0
loc 155
ccs 51
cts 51
cp 1
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 3
B search() 0 39 10
createResult() 0 1 ?
getToken() 0 1 ?
getKeywordType() 0 1 ?
A isRisingMetric() 0 4 1
B buildQuery() 0 61 2
1
<?php declare(strict_types=1);
2
3
namespace GSoares\GoogleTrends\Search;
4
5
use GSoares\GoogleTrends\Error\GoogleTrendsException;
6
use GSoares\GoogleTrends\Result\RelatedResult;
7
use GSoares\GoogleTrends\Result\ExploreResultCollection;
8
use GSoares\GoogleTrends\Result\RelatedResultCollection;
9
use GSoares\GoogleTrends\Result\ResultCollectionInterface;
10
11
/**
12
 * @author Gabriel Felipe Soares <[email protected]>
13
 */
14
abstract class AbstractRelatedSearch implements SearchInterface
15
{
16
    protected const TRENDS_URL = 'https://trends.google.com';
17
    protected const RELATED_SEARCH_URL = 'https://trends.google.com/trends/api/widgetdata/relatedsearches';
18
19
    /**
20
     * @var ExploreSearch
21
     */
22
    protected $exploreSearch;
23
24
    /**
25
     * @var SearchRequest
26
     */
27
    protected $searchRequest;
28
29 9
    public function __construct(ExploreSearch $exploreSearch = null, SearchRequest $searchRequest = null)
30
    {
31 9
        $this->searchRequest = $searchRequest ?: new SearchRequest();
32 9
        $this->exploreSearch = $exploreSearch ?: new ExploreSearch($this->searchRequest);
33 9
    }
34
35
    /**
36
     * @param SearchFilter $searchFilter
37
     *
38
     * @return RelatedResultCollection
39
     *
40
     * @throws GoogleTrendsException
41
     */
42 9
    public function search(SearchFilter $searchFilter): ResultCollectionInterface
43
    {
44 9
        if (!$searchFilter->isConsideringRisingMetrics() && !$searchFilter->isConsideringTopMetrics()) {
45 1
            return new RelatedResultCollection('', ...[]);
46
        }
47
48 8
        $searchFilter->withToken($this->getToken($this->exploreSearch->search($searchFilter)));
49
50 8
        $searchUrl = $this->buildQuery($searchFilter);
51
52 8
        $responseDecoded = $this->searchRequest->search($searchUrl);
53
54 8
        if (!isset($responseDecoded['default']['rankedList'])) {
55 2
            throw new GoogleTrendsException(
56 2
                sprintf(
57 2
                    'Invalid google response body "%s"...',
58 2
                    substr(var_export($responseDecoded, true), 100)
59
                )
60
            );
61
        }
62
63 6
        $results = [];
64
65 6
        foreach ($responseDecoded['default']['rankedList'] as $row) {
66 6
            foreach ($row['rankedKeyword'] ?? [] as $rank) {
67 6
                if (!$searchFilter->isConsideringRisingMetrics() && $this->isRisingMetric($rank)) {
68 1
                    continue;
69
                }
70
71 6
                if (!$searchFilter->isConsideringTopMetrics() && !$this->isRisingMetric($rank)) {
72 1
                    continue;
73
                }
74
75 6
                $results[] = $this->createResult($rank);
76
            }
77
        }
78
79 4
        return new RelatedResultCollection($searchUrl, ...$results);
80
    }
81
82
    /**
83
     * @param array $data
84
     *
85
     * @return RelatedResult
86
     *
87
     * @throws GoogleTrendsException
88
     */
89
    abstract protected function createResult(array $data): RelatedResult;
90
91
    /**
92
     * @param ExploreResultCollection $resultCollection
93
     *
94
     * @return string
95
     *
96
     * @throws GoogleTrendsException
97
     */
98
    abstract protected function getToken(ExploreResultCollection $resultCollection): string;
99
100
    abstract protected function getKeywordType(): string;
101
102 4
    protected function isRisingMetric(array $row): bool
103
    {
104 4
        return strpos(($row['formattedValue'] ?? ''), '+') === 0;
105
    }
106
107 8
    private function buildQuery(SearchFilter $searchFilter): string
108
    {
109
        $request = [
110 8
            'restriction' => [
111
                'geo' => [
112 8
                    'country' => $searchFilter->getLocation(),
113
                ],
114 8
                'time' => $searchFilter->getTime(),
115 8
                'originalTimeRangeForExploreUrl' => $searchFilter->getTime(),
116
            ],
117 8
            'keywordType' => $this->getKeywordType(),
118
            'metric' => [
119
                'TOP',
120
                'RISING',
121
            ],
122
            'trendinessSettings' => [
123 8
                'compareTime' => $searchFilter->getCompareTime(),
124
            ],
125
            'requestOptions' => [
126 8
                'property' => $searchFilter->getSearchType(),
127 8
                'backend' => 'IZG',
128 8
                'category' => $searchFilter->getCategory(),
129
            ],
130 8
            'language' => 'en',
131 8
            'userCountryCode' => 'US',
132
        ];
133
134 8
        if (!empty($searchFilter->getSearchTerm())) {
135 5
            $request['restriction']['complexKeywordsRestriction'] = [
136
                'keyword' => [
137
                    [
138 5
                        'type' => 'BROAD',
139 5
                        'value' => $searchFilter->getSearchTerm(),
140
                    ],
141
                ],
142
            ];
143
        }
144
145
        $query = [
146 8
            'hl' => $searchFilter->getLanguage(),
0 ignored issues
show
Deprecated Code introduced by
The method GSoares\GoogleTrends\Sea...chFilter::getLanguage() has been deprecated with message: Will be removed, cause other languages do not work as filter. We should utilize only location

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
147 8
            'tz' => '-120',
148 8
            'req' => json_encode($request),
149 8
            'token' => $searchFilter->getToken()
150
        ];
151
152 8
        $queryString = str_replace(
153
            [
154 8
                '%3A',
155
                '%2C',
156
                '%2B'
157
            ],
158
            [
159 8
                ':',
160
                ',',
161
                '+',
162
            ],
163 8
            http_build_query($query)
164
        );
165
166 8
        return self::RELATED_SEARCH_URL . '?' . $queryString;
167
    }
168
}
169