PluginProbe
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 2.22.1
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v2.22.1
4.7.2 4.7.1 4.7.0 4.6.6 4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 4.5.1 4.5.0 4.4.2 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 All 281 releases
surecart / app / src / Integrations / IntegrationService.php
IntegrationService.php
440 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SureCart\Integrations;
4
5 use SureCart\Integrations\Contracts\IntegrationInterface;
6 use SureCart\Integrations\Contracts\PurchaseSyncInterface;
7 use SureCart\Models\Integration;
8 use SureCart\Models\Purchase;
9
10 /**
11 * Base class for integrations to extend.
12 */
13 abstract class IntegrationService extends AbstractIntegration implements IntegrationInterface {
14 /**
15 * Purchase model for the integration.
16 *
17 * @var \SureCart\Models\Purchase
18 */
19 protected $purchase = null;
20
21 /**
22 * The current user for the integration.
23 *
24 * @var \WP_User
25 */
26 protected $user = null;
27
28 /**
29 * Get the slug for the integration.
30 *
31 * @return string
32 */
33 public function getName() {
34 return '';
35 }
36
37 /**
38 * Get the model for the integration.
39 *
40 * @return string
41 */
42 public function getModel() {
43 return '';
44 }
45
46
47 /**
48 * Get the logo for the integration.
49 *
50 * @return string
51 */
52 public function getLogo() {
53 return '';
54 }
55
56 /**
57 * Get the name for the integration.
58 *
59 * @return string
60 */
61 public function getLabel() {
62 return '';
63 }
64
65 /**
66 * Get the item label for the integration.
67 *
68 * @return string
69 */
70 public function getItemLabel() {
71 return '';
72 }
73
74 /**
75 * Get the item help label for the integration.
76 *
77 * @return string
78 */
79 public function getItemHelp() {
80 return '';
81 }
82
83 /**
84 * Get item listing for the integration.
85 *
86 * @param array $items The integration items.
87 * @param string $search The search query.
88 *
89 * @return array The items for the integration.
90 */
91 public function getItems( $items = [], $search = '' ) {
92 return $items;
93 }
94
95 /**
96 * Get the individual item.
97 *
98 * @param string $id Id for the record.
99 *
100 * @return array The item for the integration.
101 */
102 public function getItem( $id ) {
103 return [];
104 }
105
106 /**
107 * Enable by default.
108 *
109 * @return boolean
110 */
111 public function enabled() {
112 return true;
113 }
114
115 /**
116 * Map this class methods to specific events.
117 *
118 * @var array
119 */
120 protected $methods_map = [
121 'surecart/purchase_created' => 'onPurchaseCreated',
122 'surecart/purchase_invoked' => 'onPurchaseInvoked',
123 'surecart/purchase_revoked' => 'onPurchaseRevoked',
124 ];
125
126 /**
127 * Bootstrap the integration.
128 */
129 public function bootstrap() {
130 // index and list.
131 add_filter( "surecart/integrations/providers/list/{$this->getModel()}", [ $this, 'indexProviders' ], 9 );
132 add_filter( "surecart/integrations/providers/find/{$this->getName()}", [ $this, 'findProvider' ], 9 );
133
134 // get items.
135 add_filter( "surecart/integrations/providers/{$this->getName()}/{$this->getModel()}/items", [ $this, 'getItems' ], 9, 2 );
136 add_filter( "surecart/integrations/providers/{$this->getName()}/item", [ $this, '_getItem' ], 9, 2 );
137
138 // implement purchase events if purchase sync interface is implemented.
139 if ( is_subclass_of( $this, PurchaseSyncInterface::class ) ) {
140 add_action( 'surecart/purchase_created', [ $this, 'callMethod' ], 9 );
141 add_action( 'surecart/purchase_invoked', [ $this, 'callMethod' ], 9 );
142 add_action( 'surecart/purchase_revoked', [ $this, 'callMethod' ], 9 );
143 add_action( 'surecart/purchase_updated', [ $this, 'onPurchaseUpdated' ], 9, 2 );
144 }
145 }
146
147 /**
148 * Get the current purchase.
149 *
150 * @return \SureCart\Models\Purchase|null;
151 */
152 public function getPurchase() {
153 return $this->purchase;
154 }
155
156 public function getPurchaseId() {
157 return $this->purchase->id ?? null;
158 }
159
160 /**
161 * Get the user.
162 *
163 * @return \WP_User|null;
164 */
165 public function getUser() {
166 return $this->purchase->getWPUser();
167 }
168
169 /**
170 * The purchase has been updated.
171 * This is extendable, but is also abtracted into
172 * invoke/revoke and quantity update methods.
173 *
174 * @param Purchase $purchase The purchase.
175 * @param object $request The request.
176 *
177 * @return void
178 */
179 public function onPurchaseUpdated( Purchase $purchase, $request ) {
180 $this->purchase = $purchase;
181
182 $data = (object) $request->data->object ?? null;
183 $previous = (object) $request->data->previous_attributes ?? null;
184
185 // we need data or a previous.
186 if ( empty( $data ) || empty( $previous ) ) {
187 return;
188 }
189
190 // product has changed, let's revoke access to the old one
191 // and provide access to the new one.
192 if ( ! empty( $previous->product ) && $data->product !== $previous->product ) {
193 $previous_purchase = new Purchase(
194 array_merge(
195 $purchase->toArray(),
196 [
197 'product' => $previous->product,
198 'quantity' => $previous->quantity ?? 1,
199 ]
200 )
201 );
202 $this->onPurchaseProductUpdated( $purchase, $previous_purchase, $request );
203 return;
204 }
205
206 // The quantity has not changed.
207 if ( (int) $data->quantity === (int) $previous->quantity ) {
208 return;
209 }
210
211 // run quantity updated method.
212 $integrations = (array) $this->getIntegrationData( $purchase ) ?? [];
213 foreach ( $integrations as $integration ) {
214 if ( ! $integration->id ) {
215 continue;
216 }
217
218 if ( $this->purchaseIsNotMatchedWithPriceOrVariant( $integration, $purchase ) ) {
219 continue;
220 }
221
222 $this->onPurchaseQuantityUpdated(
223 $data->quantity,
224 $previous->quantity,
225 $integration,
226 $purchase->getWPUser()
227 );
228 }
229 }
230
231 /**
232 * When the purchase product is updated
233 *
234 * @param \SureCart\Models\Purchase $purchase The purchase.
235 * @param \SureCart\Models\Purchase $previous_purchase The previous purchase.
236 * @param array $request The request.
237 *
238 * @return void
239 */
240 public function onPurchaseProductUpdated( \SureCart\Models\Purchase $purchase, \SureCart\Models\Purchase $previous_purchase, $request ) {
241 $this->purchase = $purchase;
242
243 // product added.
244 $integrations = (array) $this->getIntegrationData( $purchase ) ?? [];
245 foreach ( $integrations as $integration ) {
246 if ( ! $integration->id ) {
247 continue;
248 }
249
250 if ( $this->purchaseIsNotMatchedWithPriceOrVariant( $integration, $purchase ) ) {
251 continue;
252 }
253
254 $this->onPurchaseProductAdded( $integration, $purchase->getWPUser(), $purchase );
255 }
256
257 // product removed.
258 $integrations = (array) $this->getIntegrationData( $previous_purchase ) ?? [];
259 foreach ( $integrations as $integration ) {
260 if ( ! $integration->id ) {
261 continue;
262 }
263
264 if ( $this->purchaseIsNotMatchedWithPriceOrVariant( $integration, $previous_purchase ) ) {
265 continue;
266 }
267
268 $this->onPurchaseProductRemoved( $integration, $previous_purchase->getWPUser(), $previous_purchase );
269 }
270 }
271
272 /**
273 * Method to run when the quantity updates.
274 *
275 * @param integer $quantity The new quantity.
276 * @param integer $previous The previous quantity.
277 * @param Purchase $purchase The purchase.
278 * @param array $request The request.
279 *
280 * @return void
281 */
282 public function onPurchaseQuantityUpdated( $quantity, $previous, $purchase, $request ) {
283 $this->purchase = $purchase;
284 // Allow this to be extended to provide functionality. Do nothing by default.
285 }
286
287 /**
288 * Get the item.
289 *
290 * @param string $id Id for the record.
291 *
292 * @return object
293 */
294 public function _getItem( $id ) {
295 if ( ! $this->enabled() ) {
296 return;
297 }
298 $item = (object) $this->getItem( $id );
299 $item->logo = esc_url_raw( $this->getLogo() );
300 return $item;
301 }
302
303 /**
304 * Call the method for the integration.
305 *
306 * @param \SureCart\Models\Purchase $purchase The purchase model.
307 *
308 * @return void
309 */
310 public function callMethod( $purchase ) {
311 // store the current purchase.
312 $this->purchase = $purchase;
313
314 $method = $this->methods_map[ $this->getCurrentAction() ] ?? null;
315 if ( ! $method || ! method_exists( $this, $method ) ) {
316 return;
317 }
318
319 $integrations = (array) $this->getIntegrationData( $purchase ) ?? [];
320 foreach ( $integrations as $integration ) {
321 if ( ! $integration->id ) {
322 continue;
323 }
324
325 // If the integration has a price_id or variant_id, then we need to match with specific price or variant.
326 if ( $this->purchaseIsNotMatchedWithPriceOrVariant( $integration, $purchase ) ) {
327 continue;
328 }
329
330 $user = $purchase->getWPUser();
331 if ( ! $user ) {
332 // throw new \Exception( 'No WordPress user is linked to this customer. This means any integrations will not run. Please link this customer to a WordPress user.' );
333 continue;
334 }
335
336 $this->$method( $integration, $purchase->getWPUser(), $purchase );
337 }
338 }
339
340 /**
341 * Get the current called action.
342 *
343 * @return string
344 */
345 protected function getCurrentAction() {
346 return \current_action();
347 }
348
349 /**
350 * Get the Integration data from the purchase.
351 * This normalizes the integration data and the WP user.
352 *
353 * @param \SureCart\Models\Purchase $purchase Purchase model.
354 *
355 * @return array The integration data.
356 */
357 public function getIntegrationData( $purchase ) {
358 if ( is_string( $purchase ) ) {
359 $purchase = Purchase::find( $purchase );
360 }
361 if ( is_wp_error( $purchase ) ) {
362 return;
363 }
364
365 // Get the integrations from the purchase.
366 return $this->getIntegrationsFromPurchase( $purchase );
367 }
368
369 /**
370 * Add the provider to the list.
371 *
372 * @param array $list The list of providers.
373 * @return array
374 */
375 public function indexProviders( $list = [] ) {
376 $list[] = $this->findProvider();
377 return $list;
378 }
379
380 /**
381 * Find the provider.
382 *
383 * @return array
384 */
385 public function findProvider() {
386 return [
387 'name' => $this->getName(),
388 'label' => $this->getLabel(),
389 'disabled' => ! $this->enabled(),
390 'logo' => esc_url_raw( $this->getLogo() ),
391 'item_label' => $this->getItemLabel(),
392 'item_help' => $this->getItemHelp(),
393 ];
394 }
395
396 /**
397 * Get the integration based on the current purchase.
398 *
399 * @param \SureCart\Models\Purchase $purchase The purchase.
400 *
401 * @return array
402 */
403 public function getIntegrationsFromPurchase( $purchase ) {
404 // we need a product id.
405 $product_id = $purchase->product_id ?? null;
406 if ( ! $product_id ) {
407 return [];
408 }
409
410 $query = Integration::where( 'model_id', $product_id )->andWhere( 'provider', $this->getName() );
411
412 return (array) $query->get();
413 }
414
415 /**
416 * Check if the integration does not match with purchase price or variant.
417 *
418 * @param Integration $integration
419 * @param Purchase $purchase
420 *
421 * @return boolean
422 */
423 public function purchaseIsNotMatchedWithPriceOrVariant( $integration, $purchase ): bool {
424 // Get Purchase price and variant.
425 $price_id = $purchase->price->id ?? $purchase->price ?? null;
426 $variant_id = $purchase->variant->id ?? $purchase->variant ?? null;
427
428 // If integration has price_id or variant_id,
429 // then we need to match with specific price or variant.
430 if (
431 ( ! empty( $integration->price_id ) && $integration->price_id !== $price_id )
432 || ( ! empty( $integration->variant_id ) && $integration->variant_id !== $variant_id )
433 ) {
434 return true;
435 }
436
437 return false;
438 }
439 }
440