Giphy   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 87
c 1
b 0
f 0
dl 0
loc 239
rs 10
wmc 17

10 Methods

Rating   Name   Duplication   Size   Complexity  
A pre_dispatch() 0 6 1
A trackStats() 0 3 1
A action_getTrending() 0 22 2
A action_index() 0 20 2
A setConfig() 0 12 1
A action_getSearchResults() 0 23 2
A sendResults() 0 11 1
A prepareImageResults() 0 24 3
A normalizeUrl() 0 5 1
A request() 0 19 3
1
<?php
2
3
/**
4
 * Functions to interact with the Giphy API and return JSON results to the giphy plugin
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * @version 2.0 dev
11
 *
12
 */
13
14
namespace ElkArte\Controller;
15
16
use ElkArte\AbstractController;
17
use ElkArte\Action;
18
use ElkArte\Errors\Errors;
0 ignored issues
show
Bug introduced by
The type ElkArte\Errors\Errors was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
20
/**
21
 * Functions to interact with the Giphy API and return JSON results to the giphy plugin
22
 */
23
class Giphy extends AbstractController
24
{
25
	/** @var string $baseApiUrl The base API URL for Giphy. */
26
	protected $baseApiUrl = 'https://api.giphy.com/v1/';
27
28
	/** @var string The API key used for authentication. */
29
	protected $apiKey;
30
31
	/** @var array default values to pass to the Giphy API */
32
	protected $config = [
33
		'random_id' => null,
34
		'rating' => 'g',
35
		'lang' => 'en',
36
		'limit' => 28,
37
	];
38
39
	/**
40
	 * pre_dispatch, called before all other methods.  Sets the Giphy API key for the Dispatch class.
41
	 *
42
	 * This method retrieves the Giphy API key from the global $modSettings variable
43
	 * @return void
44
	 */
45
	public function pre_dispatch()
46
	{
47
		global $modSettings;
48
49
		// The default is a rate limited 42 search requests an hour and 1000 search requests a day
50
		$this->apiKey = $modSettings['giphyApiKey'] ?? 'fpjXDpZ1cJ0qoqol3BVZz76YHZlv1uB2';
51
	}
52
53
	/**
54
	 * Index action, based on the SA sends control to the right method.
55
	 *
56
	 * @return void
57
	 */
58
	public function action_index()
59
	{
60
		global $context, $modSettings;
61
62
		if (empty($modSettings['enableGiphy']))
63
		{
64
			return;
65
		}
66
67
		$this->setConfig();
68
69
		$subActions = [
70
			'search' => [$this, 'action_getSearchResults'],
71
			'trending' => [$this, 'action_getTrending'],
72
		];
73
74
		$action = new Action('giphy');
75
		$subAction = $action->initialize($subActions, 'trending');
76
		$context['sub_action'] = $subAction;
77
		$action->dispatch($subAction);
78
	}
79
80
	/**
81
	 * Sets the configuration settings for the object.
82
	 *
83
	 * @return array The updated configuration settings after merging with the existing configuration.
84
	 */
85
	public function setConfig()
86
	{
87
		global $modSettings;
88
89
		$config = [
90
			'rating' => $modSettings['giphyRating'] ?? 'g',
91
			'lang' => $modSettings['giphyLanguage'] ?? 'en',
92
		];
93
94
		$this->config = array_replace($this->config, $config);
95
96
		return $this->config;
97
	}
98
99
	/**
100
	 * Tracks the statistics for a given action.
101
	 *
102
	 * @return bool Returns false indicating that the statistics tracking is not needed
103
	 */
104
	public function trackStats($action = '')
105
	{
106
		return false;
107
	}
108
109
	/**
110
	 * Retrieves trending GIFs.
111
	 *
112
	 * @return bool The trending GIFs and pagination information.
113
	 */
114
	public function action_getTrending()
115
	{
116
		checkSession('get');
117
118
		is_not_guest();
119
120
		$result = $this->request('gifs/trending', [
121
			'random_id' => $this->config['random_id'],
122
			'rating' => $this->config['rating'],
123
			'limit' => $this->config['limit'],
124
			'offset' => $this->_req->getQuery('offset', 'intval', 0)
125
		], $error);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $error seems to be never defined.
Loading history...
126
127
		if ($error)
128
		{
129
			return $this->sendResults([], []);
130
		}
131
132
		$images = $this->prepareImageResults($result);
133
		$result['pagination']['limit'] = $this->config['limit'];
134
135
		return $this->sendResults($images, $result);
136
	}
137
138
	/**
139
	 * Retrieves search results for GIFs based on the provided query.
140
	 *
141
	 * @return bool The search results and pagination information.
142
	 */
143
	public function action_getSearchResults()
144
	{
145
		checkSession('get');
146
147
		is_not_guest();
148
149
		$result = $this->request('gifs/search', [
150
			'q' => $this->_req->getQuery('q', 'trim', ''),
151
			'random_id' => $this->config['random_id'],
152
			'rating' => $this->config['rating'],
153
			'limit' => $this->config['limit'],
154
			'offset' => $this->_req->getQuery('offset', 'intval', 0)
155
		], $error);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $error seems to be never defined.
Loading history...
156
157
		if ($error)
158
		{
159
			return $this->sendResults([], []);
160
		}
161
162
		$images =  $this->prepareImageResults($result);
163
		$result['pagination']['limit'] = $this->config['limit'];
164
165
		return $this->sendResults($images,$result);
166
	}
167
168
	/**
169
	 * Sets the results in context so the JSON template can deliver them.
170
	 *
171
	 * @param array $images An array of trending GIFs.
172
	 * @param array $result The pagination and meta information.
173
	 *
174
	 * @return bool Returns true after sending the results.
175
	 */
176
	public function sendResults($images, $result)
177
	{
178
		global $context;
179
180
		setJsonTemplate();
181
		$context['json_data'] = [
182
			'giphy' => $images,
183
			'data' => $result
184
		];
185
186
		return true;
187
	}
188
189
	/**
190
	 * Sends a request to the GIPHY API.
191
	 *
192
	 * @param string $path The API endpoint path.
193
	 * @param array $params The additional parameters for the request (optional).
194
	 * @param string &$error A variable to hold any error message (optional).
195
	 *
196
	 * @return array The response from the API as an associative array, or an empty array if there was an error.
197
	 */
198
	public function request(string $path, array $params = [], string &$error = null): array
199
	{
200
		$result = [];
201
		$params = ['api_key' => $this->apiKey] + $params;
202
		$path .= '?' . http_build_query($params, '','&');
203
204
		require_once(SUBSDIR . '/Package.subs.php');
205
		$body = fetch_web_data($this->baseApiUrl . $path);
206
		if ($body !== false)
207
		{
208
			$contents = json_decode($body, true);
209
210
			return is_array($contents) ? $contents : [];
211
		}
212
213
		$error = true;
214
		Errors::instance()->log_error('GIPHY API error');
215
216
		return $result;
217
	}
218
219
	/**
220
	 * Prepares the results from the API response.
221
	 *
222
	 * @param array $result The API response containing the image data.
223
	 * @return array The prepared image results.
224
	 */
225
	protected function prepareImageResults($result): array
226
	{
227
		$images = [];
228
229
		if (is_array($result))
0 ignored issues
show
introduced by
The condition is_array($result) is always true.
Loading history...
230
		{
231
			foreach ($result['data'] as $data)
232
			{
233
				$fixedHeight = $data['images']['fixed_height']['url'];
234
				$fixedHeightStill = $data['images']['fixed_height_still']['url'];
235
236
				$fixedHeightSmall = $data['images']['fixed_height_small']['url'] ?? $fixedHeight;
237
				$fixedHeightSmallStill = $data['images']['fixed_height_small_still']['url'] ?? $fixedHeightStill;
238
239
				$images[$data['id']] = [
240
					'title' => $data['title'],
241
					'insert' => $this->normalizeUrl($fixedHeight),
242
					'src' => $this->normalizeUrl($fixedHeightSmall),
243
					'thumbnail' => $this->normalizeUrl($fixedHeightSmallStill),
244
				];
245
			}
246
		}
247
248
		return $images;
249
	}
250
251
	/**
252
	 * Normalizes a given URL.
253
	 *
254
	 * @param string $url The URL to be normalized.
255
	 * @return string The normalized URL without query parameters or fragments.
256
	 */
257
	protected function normalizeUrl($url)
258
	{
259
		$parts = parse_url($url);
260
261
		return sprintf('%s://%s%s', $parts['scheme'], $parts['host'], $parts['path']);
262
	}
263
}
264