Completed
Push — master ( b7038b...d64f6f )
by Nate
05:37 queued 03:37
created

Objects::resolveObjectIdFromElementId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 0
cts 24
cp 0
rs 9.488
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
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
     */
164
    public function syncToHubSpot(
165
        ElementInterface $element,
166
        string $objectId = null,
167
        $transformer = null
168
    ): bool {
169
        /** @var Element $element */
170
171
        $id = $objectId ?: $this->resolveObjectIdFromElement($element);
172
173
        // Get callable used to create payload
174
        if (null === ($transformer = TransformerHelper::resolveTransformer($transformer))) {
175
            $transformer = HubSpot::getInstance()->getSettings()->getSyncUpsertPayloadTransformer();
176
        }
177
178
        // Create payload
179
        $payload = call_user_func_array(
180
            $transformer,
181
            [
182
                $element,
183
                $this,
184
                $id
185
            ]
186
        );
187
188
        $response = $this->upsertToHubSpot($payload, $id);
189
190
        return $this->handleSyncToHubSpotResponse(
191
            $response,
192
            $element,
193
            $id,
194
            $transformer
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
     */
266
    public function addAssociation(
267
        ElementInterface $element,
268
        string $id
269
    ) {
270
        /** @var IntegrationAssociationQuery $query */
271
        if (null === ($query = $element->getFieldValue($this->handle))) {
272
            HubSpot::warning("Field is not available on element.");
273
            return false;
274
        };
275
276
        $associations = ArrayHelper::index($query->all(), 'objectId');
277
278
        if (!array_key_exists($id, $associations)) {
279
            $associations[$id] = $association = new ObjectAssociation([
280
                'element' => $element,
281
                'field' => $this,
282
                'siteId' => SiteHelper::ensureSiteId($element->siteId),
283
                'objectId' => $id
284
            ]);
285
286
            $query->setCachedResult(array_values($associations));
287
288
            return $association->save();
289
        }
290
291
        return true;
292
    }
293
294
    /**
295
     * @param ResponseInterface $response
296
     * @param ElementInterface $element
297
     * @param string|null $objectId
298
     * @param string|null|callable $transformer
299
     * @return bool
300
     */
301
    protected function handleSyncToHubSpotResponse(
302
        ResponseInterface $response,
303
        ElementInterface $element,
304
        string $objectId = null,
305
        $transformer = 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