PluginProbe
Packeta / 1.5.2
Packeta v1.5.2
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / src / Packetery / Module / Options / FeatureFlagManager.php

FeatureFlagManager.php in Packeta 1.5.2, at src/Packetery/Module/Options/FeatureFlagManager.php

222 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class FeatureFlagManager
4 *
5 * @package Packetery
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Options;
11
12 use DateTimeImmutable;
13 use Exception;
14 use Packetery\Core\Helper;
15 use Packetery\Module\Plugin;
16 use PacketeryGuzzleHttp\Client;
17 use PacketeryGuzzleHttp\Exception\GuzzleException;
18 use PacketeryGuzzleHttp\PacketeryPsr7\Response;
19 use PacketeryLatte\Engine;
20
21 /**
22 * Class FeatureFlagManager
23 *
24 * @package Packetery
25 */
26 class FeatureFlagManager {
27
28 private const ENDPOINT_URL = 'https://pes-features-prod-pes.prod.packeta-com.codenow.com/v1/wp';
29 private const VALID_FOR_HOURS = 4;
30 private const FLAGS_OPTION_ID = 'packeta_feature_flags';
31 private const TRANSIENT_SHOW_SPLIT_MESSAGE = 'packeta_show_split_message';
32 public const ACTION_HIDE_SPLIT_MESSAGE = 'dismiss_split_message';
33
34 private const FLAG_LAST_DOWNLOAD = 'lastDownload';
35 private const FLAG_SPLIT_ACTIVE = 'splitActive';
36
37 /**
38 * Guzzle client.
39 *
40 * @var Client Guzzle client.
41 */
42 private $client;
43
44 /**
45 * Latte engine.
46 *
47 * @var Engine
48 */
49 private $latteEngine;
50
51 /**
52 * Options provider.
53 *
54 * @var Provider
55 */
56 private $optionsProvider;
57
58 /**
59 * Downloader constructor.
60 *
61 * @param Client $guzzleClient Guzzle client.
62 * @param Engine $latteEngine Latte engine.
63 * @param Provider $optionsProvider Options provider.
64 */
65 public function __construct( Client $guzzleClient, Engine $latteEngine, Provider $optionsProvider ) {
66 $this->client = $guzzleClient;
67 $this->latteEngine = $latteEngine;
68 $this->optionsProvider = $optionsProvider;
69 }
70
71 /**
72 * Downloads flags.
73 *
74 * @return array
75 * @throws Exception From DateTimeImmutable.
76 */
77 private function fetchFlags(): array {
78 /**
79 * Guzzle response.
80 *
81 * @var Response $response Guzzle response.
82 */
83 try {
84 $response = $this->client->get(
85 self::ENDPOINT_URL,
86 [
87 'query' => [
88 'api_key' => $this->optionsProvider->get_api_key(),
89 ],
90 ]
91 );
92 } catch ( GuzzleException $exception ) {
93 // We need to not block the presentation. TODO: solve logging.
94 return [];
95 }
96 $responseJson = $response->getBody()->getContents();
97 $responseDecoded = json_decode( $responseJson, true );
98
99 $lastDownload = new DateTimeImmutable( 'now', new \DateTimeZone( 'UTC' ) );
100 $flags = [
101 self::FLAG_SPLIT_ACTIVE => (bool) $responseDecoded['features']['split'],
102 self::FLAG_LAST_DOWNLOAD => $lastDownload->format( Helper::MYSQL_DATETIME_FORMAT ),
103 ];
104
105 update_option( self::FLAGS_OPTION_ID, $flags );
106
107 return $flags;
108 }
109
110 /**
111 * Gets or downloads flags.
112 *
113 * @return array
114 * @throws Exception From DateTimeImmutable.
115 */
116 private function getFlags(): array {
117 static $flags;
118
119 if ( ! isset( $flags ) ) {
120 $flags = get_option( self::FLAGS_OPTION_ID );
121 }
122
123 $hasApiKey = ( null !== $this->optionsProvider->get_api_key() );
124 if ( false === $flags ) {
125 if ( ! $hasApiKey ) {
126 $flags = [];
127
128 return $flags;
129 }
130
131 $flags = $this->fetchFlags();
132
133 return $flags;
134 }
135
136 if ( $hasApiKey && isset( $flags[ self::FLAG_LAST_DOWNLOAD ] ) ) {
137 $now = new DateTimeImmutable( 'now', new \DateTimeZone( 'UTC' ) );
138 $lastUpdate = DateTimeImmutable::createFromFormat(
139 Helper::MYSQL_DATETIME_FORMAT,
140 $flags[ self::FLAG_LAST_DOWNLOAD ],
141 new \DateTimeZone( 'UTC' )
142 );
143 $ageHours = ( ( $now->getTimestamp() - $lastUpdate->getTimestamp() ) / HOUR_IN_SECONDS );
144 if ( $ageHours >= self::VALID_FOR_HOURS ) {
145 $oldFlags = $flags;
146 $flags = $this->fetchFlags();
147 }
148
149 if (
150 isset( $oldFlags, $flags[ self::FLAG_SPLIT_ACTIVE ] ) &&
151 false === $oldFlags[ self::FLAG_SPLIT_ACTIVE ] &&
152 true === $flags[ self::FLAG_SPLIT_ACTIVE ]
153 ) {
154 set_transient( self::TRANSIENT_SHOW_SPLIT_MESSAGE, 'yes' );
155 }
156 }
157
158 return $flags;
159 }
160
161 /**
162 * Tells if split is active.
163 *
164 * @return bool
165 * @throws Exception From DateTimeImmutable.
166 */
167 public function isSplitActive(): bool {
168 $flags = $this->getFlags();
169 if ( isset( $flags[ self::FLAG_SPLIT_ACTIVE ] ) ) {
170 return (bool) $flags[ self::FLAG_SPLIT_ACTIVE ];
171 }
172
173 return false;
174 }
175
176 /**
177 * Dismiss split notice.
178 *
179 * @return void
180 */
181 public function dismissSplitActivationNotice(): void {
182 delete_transient( self::TRANSIENT_SHOW_SPLIT_MESSAGE );
183 }
184
185 /**
186 * Determines whether to display split notice.
187 *
188 * @return bool
189 */
190 public function hasSplitActivationNotice(): bool {
191 return ( 'yes' === get_transient( self::TRANSIENT_SHOW_SPLIT_MESSAGE ) );
192 }
193
194 /**
195 * Print split activation notice.
196 *
197 * @return void
198 */
199 public function renderSplitActivationNotice(): void {
200 $dismissUrl = add_query_arg( [ Plugin::PARAM_PACKETERY_ACTION => self::ACTION_HIDE_SPLIT_MESSAGE ] );
201 $this->latteEngine->render(
202 PACKETERY_PLUGIN_DIR . '/template/admin-notice.latte',
203 [
204 'message' => [
205 'type' => 'warning',
206 'escape' => false,
207 'message' => sprintf(
208 // translators: 1: documentation link start 2: link end 3: dismiss link start 4: link end.
209 __(
210 'We have just enabled new options for setting Packeta pickup points. You can now choose a different price for Z-Box and pickup points in the carrier settings. More information can be found in %1$sthe plugin documentation%2$s. %3$sDismiss this message%4$s',
211 'packeta'
212 ),
213 ...Plugin::createLinkParts( 'https://github.com/Zasilkovna/WooCommerce/wiki', '_blank' ),
214 ...Plugin::createLinkParts( $dismissUrl, null, 'button button-primary' )
215 ),
216 ],
217 ]
218 );
219 }
220
221 }
222