Completed
Push — develop ( c1b913...0d1acc )
by Nate
04:18
created

Objects   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 380
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 12
dl 0
loc 380
ccs 0
cts 185
cp 0
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
upsertToHubSpot() 0 4 ?
getObjectIdFromResponse() 0 1 ?
A recordClass() 0 4 1
A getConnection() 0 4 1
A getCache() 0 4 1
A syncToHubSpot() 0 32 3
B syncFromHubSpot() 0 52 7
A addAssociation() 0 27 3
A handleSyncToHubSpotResponse() 0 32 5
A resolveObjectIdFromElement() 0 8 1
A resolveObjectIdFromElementId() 0 27 2
A resolveElementIdFromObjectId() 0 27 2
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/hubspot/license
6
 * @link       https://www.flipboxfactory.com/software/hubspot/
7
 */
8
9
namespace flipbox\craft\hubspot\fields;
10
11
use Craft;
12
use craft\base\Element;
13
use craft\base\ElementInterface;
14
use craft\helpers\ArrayHelper;
15
use flipbox\craft\ember\helpers\SiteHelper;
16
use flipbox\craft\hubspot\fields\actions\SyncItemFrom;
17
use flipbox\craft\hubspot\fields\actions\SyncItemTo;
18
use flipbox\craft\hubspot\fields\actions\SyncTo;
19
use flipbox\craft\hubspot\helpers\TransformerHelper;
20
use flipbox\craft\hubspot\HubSpot;
21
use flipbox\craft\hubspot\records\ObjectAssociation;
22
use flipbox\craft\hubspot\transformers\PopulateElementErrorsFromResponse;
23
use flipbox\craft\hubspot\transformers\PopulateElementErrorsFromUpsertResponse;
24
use flipbox\craft\integration\fields\Integrations;
25
use flipbox\craft\integration\queries\IntegrationAssociationQuery;
26
use flipbox\hubspot\connections\ConnectionInterface;
27
use Psr\Http\Message\ResponseInterface;
28
use Psr\SimpleCache\CacheInterface;
29
30
/**
31
 * @author Flipbox Factory <[email protected]>
32
 * @since 1.0.0
33
 */
34
abstract class Objects extends Integrations implements ObjectsFieldInterface
35
{
36
    /**
37
     * @inheritdoc
38
     */
39
    const TRANSLATION_CATEGORY = 'hubspot';
40
41
    /**
42
     * @inheritdoc
43
     */
44
    const INPUT_TEMPLATE_PATH = 'hubspot/_components/fieldtypes/Objects/input';
45
46
    /**
47
     * @inheritdoc
48
     */
49
    const INPUT_ITEM_TEMPLATE_PATH = 'hubspot/_components/fieldtypes/Objects/_inputItem';
50
51
    /**
52
     * @inheritdoc
53
     */
54
    const SETTINGS_TEMPLATE_PATH = 'hubspot/_components/fieldtypes/Objects/settings';
55
56
    /**
57
     * @inheritdoc
58
     */
59
    const ACTION_PREFORM_ACTION_PATH = 'hubspot/cp/fields/perform-action';
60
61
    /**
62
     * @inheritdoc
63
     */
64
    const ACTION_CREATE_ITEM_PATH = 'hubspot/cp/fields/create-item';
65
66
    /**
67
     * @inheritdoc
68
     */
69
    const ACTION_ASSOCIATION_ITEM_PATH = 'hubspot/cp/objects/associate';
70
71
    /**
72
     * @inheritdoc
73
     */
74
    const ACTION_DISSOCIATION_ITEM_PATH = 'hubspot/cp/objects/dissociate';
75
76
    /**
77
     * @inheritdoc
78
     */
79
    const ACTION_PREFORM_ITEM_ACTION_PATH = 'hubspot/cp/fields/perform-item-action';
80
81
    /**
82
     * Indicates whether the full sync operation should be preformed if a matching HubSpot Object was found but not
83
     * currently associated to the element.  For example, when attempting to Sync a Craft User to a HubSpot Contact, if
84
     * the HubSpot Contact already exists; true would override data in HubSpot while false would just perform
85
     * an association (note, a subsequent sync operation could be preformed)
86
     * @var bool
87
     *
88
     * @deprecated
89
     */
90
    public $syncToHubSpotOnMatch = false;
91
92
    /**
93
     * @inheritdoc
94
     */
95
    protected $defaultAvailableActions = [
96
        SyncTo::class
97
    ];
98
99
    /**
100
     * @inheritdoc
101
     */
102
    protected $defaultAvailableItemActions = [
103
        SyncItemFrom::class,
104
        SyncItemTo::class,
105
    ];
106
107
    /**
108
     * @param array $payload
109
     * @param string|null $id
110
     * @return ResponseInterface
111
     */
112
    abstract protected function upsertToHubSpot(
113
        array $payload,
114
        string $id = null
115
    ): ResponseInterface;
116
117
    /**
118
     * @param ResponseInterface $response
119
     * @return string|null
120
     */
121
    abstract protected function getObjectIdFromResponse(ResponseInterface $response);
122
123
    /**
124
     * @inheritdoc
125
     */
126
    public static function recordClass(): string
127
    {
128
        return ObjectAssociation::class;
129
    }
130
131
    /*******************************************
132
     * CONNECTION
133
     *******************************************/
134
135
    /**
136
     * @return ConnectionInterface
137
     * @throws \flipbox\craft\integration\exceptions\ConnectionNotFound
138
     */
139
    public function getConnection(): ConnectionInterface
140
    {
141
        return HubSpot::getInstance()->getConnections()->get();
142
    }
143
144
    /*******************************************
145
     * CACHE
146
     *******************************************/
147
148
    /**
149
     * @return CacheInterface
150
     */
151
    public function getCache(): CacheInterface
152
    {
153
        return HubSpot::getInstance()->getCache()->get();
154
    }
155
156
157
    /*******************************************
158
     * SYNC TO
159
     *******************************************/
160
161
    /**
162
     * @inheritdoc
163
     * @throws \Throwable
164
     */
165
    public function syncToHubSpot(
166
        ElementInterface $element,
167
        string $objectId = null,
168
        $transformer = null
169
    ): bool {
170
        /** @var Element $element */
171
172
        $id = $objectId ?: $this->resolveObjectIdFromElement($element);
173
174
        // Get callable used to create payload
175
        if (null === ($transformer = TransformerHelper::resolveTransformer($transformer))) {
176
            $transformer = HubSpot::getInstance()->getSettings()->getSyncUpsertPayloadTransformer();
177
        }
178
179
        // Create payload
180
        $payload = call_user_func_array(
181
            $transformer,
182
            [
183
                $element,
184
                $this,
185
                $id
186
            ]
187
        );
188
189
        $response = $this->upsertToHubSpot($payload, $id);
190
191
        return $this->handleSyncToHubSpotResponse(
192
            $response,
193
            $element,
194
            $id
195
        );
196
    }
197
198
    /*******************************************
199
     * SYNC FROM
200
     *******************************************/
201
202
    /**
203
     * @@inheritdoc
204
     * @throws \Throwable
205
     * @throws \craft\errors\ElementNotFoundException
206
     * @throws \yii\base\Exception
207
     */
208
    public function syncFromHubSpot(
209
        ElementInterface $element,
210
        string $objectId = null,
211
        $transformer = null
212
    ): bool {
213
214
        $id = $objectId ?: $this->resolveObjectIdFromElement($element);
215
216
        if (null === $id) {
217
            return false;
218
        }
219
220
        $response = $this->readFromHubSpot($id);
221
222
        if (($response->getStatusCode() < 200 || $response->getStatusCode() >= 300)) {
223
            call_user_func_array(
224
                new PopulateElementErrorsFromResponse(),
225
                [
226
                    $response,
227
                    $element,
228
                    $this,
229
                    $id
230
                ]
231
            );
232
            return false;
233
        }
234
235
        // Get callable used to populate element
236
        if (null === ($transformer = TransformerHelper::resolveTransformer($transformer))) {
237
            $transformer = HubSpot::getInstance()->getSettings()->getSyncPopulateElementTransformer();
238
        }
239
240
        // Populate element
241
        call_user_func_array(
242
            $transformer,
243
            [
244
                $response,
245
                $element,
246
                $this,
247
                $id
248
            ]
249
        );
250
251
        if ($objectId !== null) {
252
            $this->addAssociation(
253
                $element,
254
                $id
255
            );
256
        }
257
258
        return Craft::$app->getElements()->saveElement($element);
259
    }
260
261
    /**
262
     * @param ElementInterface|Element $element
263
     * @param string $id
264
     * @return bool
265
     * @throws \Throwable
266
     */
267
    public function addAssociation(
268
        ElementInterface $element,
269
        string $id
270
    ) {
271
        /** @var IntegrationAssociationQuery $query */
272
        if (null === ($query = $element->getFieldValue($this->handle))) {
273
            HubSpot::warning("Field is not available on element.");
274
            return false;
275
        };
276
277
        $associations = ArrayHelper::index($query->all(), 'objectId');
278
279
        if (!array_key_exists($id, $associations)) {
280
            $associations[$id] = $association = new ObjectAssociation([
281
                'element' => $element,
282
                'field' => $this,
283
                'siteId' => SiteHelper::ensureSiteId($element->siteId),
284
                'objectId' => $id
285
            ]);
286
287
            $query->setCachedResult(array_values($associations));
288
289
            return $association->save();
290
        }
291
292
        return true;
293
    }
294
295
    /**
296
     * @param ResponseInterface $response
297
     * @param ElementInterface $element
298
     * @param string|null $objectId
299
     * @return bool
300
     * @throws \Throwable
301
     */
302
    protected function handleSyncToHubSpotResponse(
303
        ResponseInterface $response,
304
        ElementInterface $element,
305
        string $objectId = null
306
    ): bool {
307
308
        /** @var Element $element */
309
310
        if (!($response->getStatusCode() >= 200 && $response->getStatusCode() <= 299)) {
311
            call_user_func_array(
312
                new PopulateElementErrorsFromUpsertResponse(),
313
                [
314
                    $response,
315
                    $element,
316
                    $this,
317
                    $objectId
318
                ]
319
            );
320
            return false;
321
        }
322
323
        if (empty($objectId)) {
324
            if (null === ($objectId = $this->getObjectIdFromResponse($response))) {
325
                HubSpot::error("Unable to determine object id from response");
326
                return false;
327
            };
328
329
            return $this->addAssociation($element, $objectId);
330
        }
331
332
        return true;
333
    }
334
335
    /**
336
     * @param ElementInterface|Element $element
337
     * @return null|string
338
     */
339
    public function resolveObjectIdFromElement(
340
        ElementInterface $element
341
    ) {
342
        return $this->resolveObjectIdFromElementId(
343
            $element->getId(),
344
            $element->siteId
345
        );
346
    }
347
348
    /**
349
     * @param int $elementId
350
     * @param int|null $siteId
351
     * @return bool|false|string|null
352
     */
353
    public function resolveObjectIdFromElementId(
354
        int $elementId,
355
        int $siteId = null
356
    ) {
357
        if (!$objectId = ObjectAssociation::find()
358
            ->select(['objectId'])
359
            ->elementId($elementId)
360
            ->fieldId($this->id)
361
            ->siteId(SiteHelper::ensureSiteId($siteId))
362
            ->scalar()
363
        ) {
364
            HubSpot::warning(sprintf(
365
                "HubSpot Object Id association was not found for element '%s'",
366
                $elementId
367
            ));
368
369
            return null;
370
        }
371
372
        HubSpot::info(sprintf(
373
            "HubSpot Object Id '%s' was found for element '%s'",
374
            $objectId,
375
            $elementId
376
        ));
377
378
        return $objectId;
379
    }
380
381
    /**
382
     * @param string $objectId
383
     * @param int|null $siteId
384
     * @return bool|false|string|null
385
     */
386
    public function resolveElementIdFromObjectId(
387
        string $objectId,
388
        int $siteId = null
389
    ) {
390
        if (!$elementId = ObjectAssociation::find()
391
            ->select(['elementId'])
392
            ->objectId($objectId)
393
            ->fieldId($this->id)
394
            ->siteId(SiteHelper::ensureSiteId($siteId))
395
            ->scalar()
396
        ) {
397
            HubSpot::warning(sprintf(
398
                "HubSpot Element Id association was not found for object '%s'",
399
                $objectId
400
            ));
401
402
            return null;
403
        }
404
405
        HubSpot::info(sprintf(
406
            "HubSpot Element Id '%s' was found for object '%s'",
407
            $elementId,
408
            $objectId
409
        ));
410
411
        return $elementId;
412
    }
413
}
414