Passed
Push — developer ( 39d2d6...c3543f )
by Radosław
17:46
created

Shop::verify()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 17
ccs 0
cts 3
cp 0
rs 9.9
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 20
1
<?php
2
3
/**
4
 * YetiForce shop file.
5
 * Modifying this file or functions that affect the footer appearance will violate the license terms!!!
6
 *
7
 * @package App
8
 *
9
 * @copyright YetiForce S.A.
10
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
11
 * @author    Mariusz Krzaczkowski <[email protected]>
12
 * @author    Radosław Skrzypczak <[email protected]>
13
 * @author    Klaudia Łozowska <[email protected]>
14
 */
15
16
namespace App\YetiForce;
17
18
use App\Cache;
19
20
/**
21
 * YetiForce shop class.
22
 */
23
final class Shop extends AbstractBase
24
{
25
	/** @var string URL */
26
	public const URL = 'https://api.yetiforce.eu/store';
27
28
	/** @var string[] Premium icons. */
29
	public const PREMIUM_ICONS = [
30
		1 => 'yfi-premium color-red-600',
31
		2 => 'yfi-enterprise color-yellow-600',
32
		3 => 'yfi-partners color-grey-600',
33
	];
34
35
	/** @var array Product categories. */
36
	public const PRODUCT_CATEGORIES = [
37
		'All' => ['label' => 'LBL_CAT_ALL', 'icon' => 'yfi-all-shop'],
38
		'Extensions' => ['label' => 'LBL_CAT_ADDONS', 'icon' => 'yfi-adds-on-shop'],
39
		'Integrations' => ['label' => 'LBL_CAT_INTEGRATIONS', 'icon' => 'yfi-integration-shop'],
40
	];
41
42
	/**
43
	 * Product instance cache.
44
	 *
45
	 * @var array
46
	 */
47
	public static array $productCache = [];
48
49
	/**
50 1
	 * Get products.
51
	 *
52 1
	 * @param string $state
53 1
	 * @param string $section
54 1
	 *
55 1
	 * @return Shop\AbstractBaseProduct[]
56 1
	 */
57 1
	public function getProducts(): array
58 1
	{
59 1
		if (empty(self::$productCache)) {
60
			$this->load();
61 1
		}
62
63
		return self::$productCache;
64 1
	}
65
66
	/**
67
	 * Get variable payments.
68
	 *
69
	 * @return array
70
	 */
71
	public static function getVariablePayments(): array
72
	{
73
		return [
74
			'business' => '[email protected]',
75
			'rm' => 2,
76 1
			'image_url' => 'https://public.yetiforce.com/shop/logo.png',
77
			'return' => \Config\Main::$site_URL . 'index.php?module=YetiForce&parent=Settings&view=Shop&status=success',
0 ignored issues
show
Bug introduced by
The type Config\Main 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...
78 1
			'cancel_return' => \Config\Main::$site_URL . 'index.php?module=YetiForce&parent=Settings&view=Shop&status=fail',
79
			'custom' => \App\YetiForce\Register::getInstanceKey() . '|' . \App\YetiForce\Register::getCrmKey(),
80
		];
81 1
	}
82
83 1
	/**
84
	 * Verification of product.
85
	 *
86 1
	 * @param string $productName
87 1
	 *
88
	 * @return bool
89
	 */
90 1
	public static function check(string $productName): bool
91
	{
92
		$className = self::getProductClass($productName);
93
		$product = new $className($productName);
94
		return $product->getStatus();
95
	}
96
97
	/**
98
	 * Verification of product with a message.
99
	 *
100
	 * @param string $productName
101
	 *
102
	 * @return array
103
	 */
104
	public static function checkWithMessage(string $productName): array
105
	{
106
		if (Cache::staticHas('Shop|checkWithMessage', $productName)) {
107
			return Cache::staticGet('Shop|checkWithMessage', $productName);
108
		}
109
		$status = $message = false;
110
		$productDetails = \App\YetiForce\Register::getProduct($productName);
111
		if ($productDetails) {
0 ignored issues
show
introduced by
$productDetails is an empty array, thus is always false.
Loading history...
Bug Best Practice introduced by
The expression $productDetails of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
112
			$interval = (new \DateTime('now', new \DateTimeZone('GMT')))->diff(new \DateTime($productDetails['expires_at'], new \DateTimeZone('GMT')));
113
			$status = $interval->invert && $interval->days > 0;
114
			if (!$status) {
115
				$message = 'LBL_SUBSCRIPTION_HAS_EXPIRED';
116
			}
117
		}
118
119
		Cache::staticSave('Shop|checkWithMessage', $productName, [$status, $message]);
120
		return [$status, $message];
121
	}
122
123
	/**
124
	 * @todo remove or replace
125 1
	 * Check alert to show for product.
126
	 *
127 1
	 * @param string $productName
128 1
	 *
129
	 * @return string
130
	 */
131 1
	public static function checkAlert(string $productName): string
132
	{
133
		$className = self::getProductClass($productName);
134
		$product = new $className($productName);
135
		return $product->getAlertMessage();
136
	}
137
138
	/**
139
	 * Get paypal URL.
140
	 * https://www.paypal.com/cgi-bin/webscr
141
	 * https://www.sandbox.paypal.com/cgi-bin/webscr.
142
	 *
143
	 * @return string
144
	 */
145
	public static function getPaypalUrl(): string
146
	{
147
		return 'https://www.paypal.com/cgi-bin/webscr';
148
	}
149
150
	/**
151
	 * Verify or show a message about invalid products.
152
	 *
153
	 * @param bool $onlyNames
154
	 * @param bool $getNames
155
	 *
156
	 * @return string
157
	 */
158
	public static function verify(bool $getNames = false): string
159
	{
160
		$names = [];
161
		$products = \App\YetiForce\Register::getProducts();
162
		foreach ($products ?? [] as $row) {
163
			$productName = $row['product'];
164
			$className = self::getProductClass($productName);
165
			$product = new $className($productName);
166
			if ($product->isExpired()) {
167
				$names[$productName] = $productName;
168
				if (!$getNames) {
169
					$names[$productName] = \App\Language::translate($productName, 'Settings::YetiForce');
170
				}
171
			}
172
		}
173
174
		return implode(', ', $names);
175
	}
176
177
	/**
178
	 * Get all available products.
179
	 *
180
	 * @return void
181
	 */
182
	public function load()
183
	{
184
		self::$productCache = [];
185
		$this->success = false;
186
		try {
187
			$client = new ApiClient();
188
			$client->send(self::URL . '/' . \App\Version::get() . '/products', 'GET');
189
			$this->error = $client->getError();
190
			if (!$this->error && 200 === $client->getStatusCode() && !\App\Json::isEmpty($client->getResponseBody())) {
191
				$this->setProducts(\App\Json::decode($client->getResponseBody()));
192
				$this->success = true;
193
			}
194
		} catch (\Throwable $e) {
195
			$this->success = false;
196
			$this->error = $e->getMessage();
197
			\App\Log::error($e->getMessage(), __METHOD__);
198
		}
199
	}
200
201
	/**
202
	 * Get product by ID.
203
	 *
204
	 * @param string $productId
205
	 *
206
	 * @return void
207
	 */
208
	public function loadProduct(string $productId)
209
	{
210
		$this->success = false;
211
		try {
212
			$client = new ApiClient();
213 1
			$client->send(self::URL . '/' . \App\Version::get() . "/products/{$productId}", 'GET');
214
			$this->error = $client->getError();
215 1
			if (!$this->error && 200 === $client->getStatusCode() && !\App\Json::isEmpty($client->getResponseBody())) {
216 1
				$this->setProducts([\App\Json::decode($client->getResponseBody())]);
217 1
				$this->success = true;
218
			}
219 1
		} catch (\Throwable $e) {
220 1
			$this->success = false;
221
			$this->error = $e->getMessage();
222
			\App\Log::error($e->getMessage(), __METHOD__);
223
		}
224
	}
225
226
	/**
227
	 * Get products.
228
	 *
229
	 * @param string $name
230
	 * @param string $section
231
	 * @param string $productId
232
	 *
233
	 * @return Shop\AbstractBaseProduct
234
	 */
235
	public static function getProduct(string $name, string $productId = ''): ?Shop\AbstractBaseProduct
236
	{
237
		if (empty(self::$productCache[$name])) {
238
			if ($productId) {
239
				(new self())->loadProduct($productId);
240
			} else {
241
				(new self())->load();
242
			}
243
		}
244
245
		return self::$productCache[$name] ?? null;
246
	}
247
248
	/**
249
	 * Get product class.
250
	 *
251
	 * @param string $name
252
	 *
253
	 * @return string
254
	 */
255
	private static function getProductClass(string $name): string
256
	{
257
		$className = '\\App\\YetiForce\\Shop\\Product\\' . $name;
258
		if (!class_exists($className)) {
259
			$className = '\\App\\YetiForce\\Shop\\Product\\YetiForceBase';
260
		}
261
		return $className;
262
	}
263
264
	/**
265
	 * Set Products to cache.
266
	 *
267
	 * @param array $products
268
	 *
269
	 * @return void
270
	 */
271
	private function setProducts(array $products)
272
	{
273
		foreach ($products as $productData) {
274
			$name = $productData['name'] ?? '';
275
			$className = self::getProductClass($name);
276
			if (!empty($productData['packages']) && ($product = $className::fromArray($productData)) && $product->isAvailable()) {
277
				self::$productCache[$product->getName()] = $product;
278
			}
279
		}
280
	}
281
}
282