Completed
Push — develop ( 76527a...6d8075 )
by Nate
03:43
created

ObjectAssociations::dissociateByIds()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 8
cp 0
rs 9.7666
c 0
b 0
f 0
cc 1
nc 1
nop 5
crap 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\hubspot\services;
10
11
use Codeception\Exception\ElementNotFound;
12
use Craft;
13
use craft\base\Element;
14
use craft\base\ElementInterface;
15
use craft\errors\ElementNotFoundException;
16
use craft\helpers\Json;
17
use flipbox\craft\sortable\associations\db\SortableAssociationQueryInterface;
18
use flipbox\craft\sortable\associations\records\SortableAssociationInterface;
19
use flipbox\craft\sortable\associations\services\SortableAssociations;
20
use flipbox\ember\exceptions\NotFoundException;
21
use flipbox\ember\helpers\SiteHelper;
22
use flipbox\ember\services\traits\records\Accessor;
23
use flipbox\ember\validators\MinMaxValidator;
24
use flipbox\hubspot\db\ObjectAssociationQuery;
25
use flipbox\hubspot\fields\Objects;
26
use flipbox\hubspot\HubSpot;
27
use flipbox\hubspot\migrations\ObjectAssociation as ObjectAssociationMigration;
28
use flipbox\hubspot\records\ObjectAssociation;
29
30
/**
31
 * @author Flipbox Factory <[email protected]>
32
 * @since 1.0.0
33
 *
34
 * @method ObjectAssociationQuery parentGetQuery($config = [])
35
 * @method ObjectAssociation create(array $attributes = [])
36
 * @method ObjectAssociation find($identifier)
37
 * @method ObjectAssociation get($identifier)
38
 * @method ObjectAssociation findByCondition($condition = [])
39
 * @method ObjectAssociation getByCondition($condition = [])
40
 * @method ObjectAssociation findByCriteria($criteria = [])
41
 * @method ObjectAssociation getByCriteria($criteria = [])
42
 * @method ObjectAssociation[] findAllByCondition($condition = [])
43
 * @method ObjectAssociation[] getAllByCondition($condition = [])
44
 * @method ObjectAssociation[] findAllByCriteria($criteria = [])
45
 * @method ObjectAssociation[] getAllByCriteria($criteria = [])
46
 */
47
class ObjectAssociations extends SortableAssociations
48
{
49
    use Accessor {
50
        getQuery as parentGetQuery;
51
    }
52
53
    /**
54
     * @inheritdoc
55
     */
56
    const SOURCE_ATTRIBUTE = ObjectAssociation::SOURCE_ATTRIBUTE;
57
58
    /**
59
     * @inheritdoc
60
     */
61
    const TARGET_ATTRIBUTE = ObjectAssociation::TARGET_ATTRIBUTE;
62
63
    /**
64
     * @inheritdoc
65
     * @throws \Throwable
66
     */
67 3
    public function init()
68
    {
69 3
        $settings = HubSpot::getInstance()->getSettings();
70 3
        $this->cacheDuration = $settings->associationsCacheDuration;
71 3
        $this->cacheDependency = $settings->associationsCacheDependency;
72
73 3
        parent::init();
74
75 3
        $this->ensureTableExists();
76 3
    }
77
78
    /**
79
     * @throws \Throwable
80
     */
81 3
    public function ensureTableExists()
82
    {
83 3
        if (!in_array(
84 3
            Craft::$app->getDb()->tablePrefix . ObjectAssociation::tableAlias(),
85 3
            Craft::$app->getDb()->getSchema()->tableNames,
86 3
            true
87
        )) {
88 3
            $this->createTable();
89
        }
90 3
    }
91
92
    /**
93
     * @return bool
94
     * @throws \Throwable
95
     */
96 3
    private function createTable(): bool
97
    {
98 3
        ob_start();
99 3
        (new ObjectAssociationMigration())->up();
100 3
        ob_end_clean();
101
102 3
        return true;
103
    }
104
105
    /**
106
     * @inheritdoc
107
     * @return ObjectAssociationQuery
108
     */
109
    public function getQuery($config = []): SortableAssociationQueryInterface
110
    {
111
        return $this->parentGetQuery($config);
112
    }
113
114
    /**
115
     * @param ElementInterface $element
116
     * @param Objects $field
117
     * @return string|null
118
     */
119
    public function findObjectIdByElement(ElementInterface $element, Objects $field)
120
    {
121
        /** @var Element $element */
122
        return $this->findObjectId($element->getId(), $field->id, $element->siteId);
123
    }
124
125
    /**
126
     * @noinspection PhpDocMissingThrowsInspection
127
     *
128
     * @param int $elementId
129
     * @param int $fieldId
130
     * @param int|null $siteId
131
     * @return null|string
132
     */
133
    public function findObjectId(int $elementId, int $fieldId, int $siteId = null)
134
    {
135
        $objectId = HubSpot::getInstance()->getObjectAssociations()->getQuery([
136
            'select' => ['objectId'],
137
            'elementId' => $elementId,
138
            'siteId' => SiteHelper::ensureSiteId($siteId),
139
            'fieldId' => $fieldId
140
        ])->scalar();
141
142
        return is_string($objectId) ? $objectId : null;
143
    }
144
145
    /**
146
     * @param int $elementId
147
     * @param int $fieldId
148
     * @param int|null $siteId
149
     * @return string
150
     * @throws NotFoundException
151
     */
152
    public function getObjectId(int $elementId, int $fieldId, int $siteId = null): string
153
    {
154
        $siteId = SiteHelper::ensureSiteId($siteId);
155
156
        if (null === ($objectId = $this->findObjectId($elementId, $fieldId, $siteId))) {
157
            throw new NotFoundException(sprintf(
158
                "Unable to find element with: Element Id: %s, Field Id: %s, Site Id: $%s",
159
                $elementId,
160
                $fieldId,
161
                $siteId
162
            ));
163
        }
164
165
        return $objectId;
166
    }
167
168
    /**
169
     * @noinspection PhpDocMissingThrowsInspection
170
     *
171
     * @param string $objectId
172
     * @param int $fieldId
173
     * @param int|null $siteId
174
     * @return null|string
175
     */
176
    public function findElementId(string $objectId, int $fieldId, int $siteId = null)
177
    {
178
        $elementId = HubSpot::getInstance()->getObjectAssociations()->getQuery([
179
            'select' => ['elementId'],
180
            'objectId' => $objectId,
181
            'siteId' => SiteHelper::ensureSiteId($siteId),
182
            'fieldId' => $fieldId
183
        ])->scalar();
184
185
        return is_string($elementId) ? $elementId : null;
186
    }
187
188
    /**
189
     * @param string $objectId
190
     * @param int $fieldId
191
     * @param int|null $siteId
192
     * @return string
193
     * @throws NotFoundException
194
     */
195
    public function getElementId(string $objectId, int $fieldId, int $siteId = null): string
196
    {
197
        $siteId = SiteHelper::ensureSiteId($siteId);
198
199
        if (null === ($elementId = $this->findElementId($objectId, $fieldId, $siteId))) {
200
            throw new NotFoundException(sprintf(
201
                "Unable to find element with: HubSpot Id: %s, Field Id: %s, Site Id: $%s",
202
                $objectId,
203
                $fieldId,
204
                $siteId
205
            ));
206
        }
207
208
        return $elementId;
209
    }
210
211
    /**
212
     * @param string $objectId
213
     * @param int $fieldId
214
     * @param int|null $siteId
215
     * @return ElementInterface|null
216
     */
217
    public function findElement(string $objectId, int $fieldId, int $siteId = null)
218
    {
219
        if (null === ($elementId = $this->findElementId($fieldId, $objectId, $siteId))) {
220
            return null;
221
        }
222
223
        return Craft::$app->getElements()->getELementById($elementId, null, $siteId);
224
    }
225
226
    /**
227
     * @param string $objectId
228
     * @param int $fieldId
229
     * @param int|null $siteId
230
     * @return ElementInterface
231
     * @throws ElementNotFoundException
232
     */
233
    public function getElement(string $objectId, int $fieldId, int $siteId = null): ElementInterface
234
    {
235
        $siteId = SiteHelper::ensureSiteId($siteId);
236
237
        if (!$element = $this->findElement($fieldId, $objectId, $siteId)) {
238
            throw new ElementNotFound(sprintf(
239
                "Unable to find element with: HubSpot Id: %s, Field Id: %s, Site Id: $%s",
240
                $objectId,
241
                $fieldId,
242
                $siteId
243
            ));
244
        }
245
246
        return $element;
247
    }
248
249
    /**
250
     * @param string $objectId
251
     * @param int $elementId
252
     * @param int $fieldId
253
     * @param int|null $siteId
254
     * @param int|null $sortOrder
255
     * @return bool
256
     */
257
    public function associateByIds(
258
        string $objectId,
259
        int $elementId,
260
        int $fieldId,
261
        int $siteId = null,
262
        int $sortOrder = null
263
    ): bool {
264
        return $this->create([
265
            'objectId' => $objectId,
266
            'elementId' => $elementId,
267
            'fieldId' => $fieldId,
268
            'siteId' => SiteHelper::ensureSiteId($siteId),
269
            'sortOrder' => $sortOrder
270
        ])->associate();
271
    }
272
273
    /**
274
     * @param string $objectId
275
     * @param int $elementId
276
     * @param int $fieldId
277
     * @param int|null $siteId
278
     * @param int|null $sortOrder
279
     * @return bool
280
     */
281
    public function dissociateByIds(
282
        string $objectId,
283
        int $elementId,
284
        int $fieldId,
285
        int $siteId = null,
286
        int $sortOrder = null
287
    ): bool {
288
        return $this->create([
289
            'objectId' => $objectId,
290
            'elementId' => $elementId,
291
            'fieldId' => $fieldId,
292
            'siteId' => SiteHelper::ensureSiteId($siteId),
293
            'sortOrder' => $sortOrder
294
        ])->dissociate();
295
    }
296
297
    /**
298
     * @inheritdoc
299
     * @return ObjectAssociationQuery
300
     */
301
    protected function associationQuery(
302
        SortableAssociationInterface $record
303
    ): SortableAssociationQueryInterface {
304
        /** @var ObjectAssociation $record */
305
        return $this->query(
306
            $record->{static::SOURCE_ATTRIBUTE},
307
            $record->fieldId,
308
            $record->siteId
309
        );
310
    }
311
312
    /**
313
     * @inheritdoc
314
     * @param ObjectAssociationQuery $query
315
     */
316
    protected function existingAssociations(
317
        SortableAssociationQueryInterface $query
318
    ): array {
319
        $source = $this->resolveStringAttribute($query, 'element');
320
        $field = $this->resolveStringAttribute($query, 'field');
321
        $site = $this->resolveStringAttribute($query, 'siteId');
322
323
        if ($source === null || $field === null || $site === null) {
324
            return [];
325
        }
326
327
        return $this->associations($source, $field, $site);
328
    }
329
330
    /**
331
     * @param $source
332
     * @param int $fieldId
333
     * @param int $siteId
334
     * @return ObjectAssociationQuery
335
     */
336
    private function query(
337
        $source,
338
        int $fieldId,
339
        int $siteId
340
    ): ObjectAssociationQuery {
341
        return $this->getQuery()
342
            ->where([
343
                static::SOURCE_ATTRIBUTE => $source,
344
                'fieldId' => $fieldId,
345
                'siteId' => $siteId
346
            ])
347
            ->orderBy(['sortOrder' => SORT_ASC]);
348
    }
349
350
    /**
351
     * @param $source
352
     * @param int $fieldId
353
     * @param int $siteId
354
     * @return array
355
     */
356
    private function associations(
357
        $source,
358
        int $fieldId,
359
        int $siteId
360
    ): array {
361
        return $this->query($source, $fieldId, $siteId)
362
            ->indexBy(static::TARGET_ATTRIBUTE)
363
            ->all();
364
    }
365
366
    /**
367
     * @inheritdoc
368
     * @param bool $validate
369
     * @throws \Exception
370
     */
371
    public function save(
372
        SortableAssociationQueryInterface $query,
373
        bool $validate = true
374
    ): bool {
375
        if ($validate === true && null !== ($field = $this->resolveFieldFromQuery($query))) {
376
            $error = '';
377
            (new MinMaxValidator([
378
                'min' => $field->min ? (int)$field->min : null,
379
                'max' => $field->max ? (int)$field->max : null
380
            ]))->validate($query, $error);
381
382
            if (!empty($error)) {
383
                HubSpot::error(sprintf(
384
                    "Hubspot Resource failed to save due to the following validation errors: '%s'",
385
                    Json::encode($error)
386
                ));
387
                return false;
388
            }
389
        }
390
391
        return parent::save($query);
392
    }
393
394
    /**
395
     * @param SortableAssociationQueryInterface $query
396
     * @return Objects|null
397
     */
398
    protected function resolveFieldFromQuery(
399
        SortableAssociationQueryInterface $query
400
    ) {
401
        if (null === ($fieldId = $this->resolveStringAttribute($query, 'field'))) {
402
            return null;
403
        }
404
405
        return HubSpot::getInstance()->getObjectsField()->findById($fieldId);
406
    }
407
408
    /**
409
     * @inheritdoc
410
     */
411
    protected static function tableAlias(): string
412
    {
413
        return ObjectAssociation::tableAlias();
414
    }
415
416
    /**
417
     * @inheritdoc
418
     */
419
    public static function recordClass(): string
420
    {
421
        return ObjectAssociation::class;
422
    }
423
}
424