Completed
Push — master ( c30a0b...37c0e6 )
by Nate
08:20
created

Objects::syncFromHubSpot()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 52
rs 8.1138
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 7
nc 12
nop 3
crap 56

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    /**
263
     * @param ElementInterface|Element $element
264
     * @param string $id
265
     * @return bool
266
     * @throws \Throwable
267
     */
268
    protected function addAssociation(
269
        ElementInterface $element,
270
        string $id
271
    ) {
272
        /** @var IntegrationAssociationQuery $query */
273
        if (null === ($query = $element->getFieldValue($this->handle))) {
274
            HubSpot::warning("Field is not available on element.");
275
            return false;
276
        };
277
278
        $associations = ArrayHelper::index($query->all(), 'objectId');
279
280
        if (!array_key_exists($id, $associations)) {
281
            $associations[$id] = $association = new ObjectAssociation([
282
                'element' => $element,
283
                'field' => $this,
284
                'siteId' => SiteHelper::ensureSiteId($element->siteId),
285
                'objectId' => $id
286
            ]);
287
288
            $query->setCachedResult(array_values($associations));
289
290
            return $association->save();
291
        }
292
293
        return true;
294
    }
295
296
    /**
297
     * @param ResponseInterface $response
298
     * @param ElementInterface $element
299
     * @param string|null $objectId
300
     * @return bool
301
     * @throws \Throwable
302
     */
303
    protected function handleSyncToHubSpotResponse(
304
        ResponseInterface $response,
305
        ElementInterface $element,
306
        string $objectId = null
307
    ): bool {
308
309
        /** @var Element $element */
310
311
        if (!($response->getStatusCode() >= 200 && $response->getStatusCode() <= 299)) {
312
            call_user_func_array(
313
                new PopulateElementErrorsFromUpsertResponse(),
314
                [
315
                    $response,
316
                    $element,
317
                    $this,
318
                    $objectId
319
                ]
320
            );
321
            return false;
322
        }
323
324
        if (empty($objectId)) {
325
            if (null === ($objectId = $this->getObjectIdFromResponse($response))) {
326
                HubSpot::error("Unable to determine object id from response");
327
                return false;
328
            };
329
330
            return $this->addAssociation($element, $objectId);
331
        }
332
333
        return true;
334
    }
335
336
    /**
337
     * @param ElementInterface|Element $element
338
     * @return null|string
339
     */
340
    protected function resolveObjectIdFromElement(
341
        ElementInterface $element
342
    ) {
343
344
        if (!$objectId = ObjectAssociation::find()
345
            ->select(['objectId'])
346
            ->elementId($element->getId())
347
            ->fieldId($this->id)
348
            ->siteId(SiteHelper::ensureSiteId($element->siteId))
349
            ->scalar()
350
        ) {
351
            HubSpot::warning(sprintf(
352
                "HubSpot Object Id association was not found for element '%s'",
353
                $element->getId()
354
            ));
355
356
            return null;
357
        }
358
359
        HubSpot::info(sprintf(
360
            "HubSpot Object Id '%s' was found for element '%s'",
361
            $objectId,
362
            $element->getId()
363
        ));
364
365
        return $objectId;
366
    }
367
}
368