Completed
Push — master ( 53e590...136153 )
by Nate
16:58 queued 14:19
created

ObjectAssociations::findElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
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\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
     * @inheritdoc
251
     * @return ObjectAssociationQuery
252
     */
253
    protected function associationQuery(
254
        SortableAssociationInterface $record
255
    ): SortableAssociationQueryInterface {
256
        /** @var ObjectAssociation $record */
257
        return $this->query(
258
            $record->{static::SOURCE_ATTRIBUTE},
259
            $record->fieldId,
260
            $record->siteId
261
        );
262
    }
263
264
    /**
265
     * @inheritdoc
266
     * @param ObjectAssociationQuery $query
267
     */
268
    protected function existingAssociations(
269
        SortableAssociationQueryInterface $query
270
    ): array {
271
        $source = $this->resolveStringAttribute($query, 'element');
272
        $field = $this->resolveStringAttribute($query, 'field');
273
        $site = $this->resolveStringAttribute($query, 'siteId');
274
275
        if ($source === null || $field === null || $site === null) {
276
            return [];
277
        }
278
279
        return $this->associations($source, $field, $site);
280
    }
281
282
    /**
283
     * @param $source
284
     * @param int $fieldId
285
     * @param int $siteId
286
     * @return ObjectAssociationQuery
287
     */
288
    private function query(
289
        $source,
290
        int $fieldId,
291
        int $siteId
292
    ): ObjectAssociationQuery {
293
        return $this->getQuery()
294
            ->where([
295
                static::SOURCE_ATTRIBUTE => $source,
296
                'fieldId' => $fieldId,
297
                'siteId' => $siteId
298
            ])
299
            ->orderBy(['sortOrder' => SORT_ASC]);
300
    }
301
302
    /**
303
     * @param $source
304
     * @param int $fieldId
305
     * @param int $siteId
306
     * @return array
307
     */
308
    private function associations(
309
        $source,
310
        int $fieldId,
311
        int $siteId
312
    ): array {
313
        return $this->query($source, $fieldId, $siteId)
314
            ->indexBy(static::TARGET_ATTRIBUTE)
315
            ->all();
316
    }
317
318
    /**
319
     * @inheritdoc
320
     * @param bool $validate
321
     * @throws \Exception
322
     */
323
    public function save(
324
        SortableAssociationQueryInterface $query,
325
        bool $validate = true
326
    ): bool {
327
        if ($validate === true && null !== ($field = $this->resolveFieldFromQuery($query))) {
328
            $error = '';
329
            (new MinMaxValidator([
330
                'min' => $field->min ? (int)$field->min : null,
331
                'max' => $field->max ? (int)$field->max : null
332
            ]))->validate($query, $error);
333
334
            if (!empty($error)) {
335
                HubSpot::error(sprintf(
336
                    "Hubspot Resource failed to save due to the following validation errors: '%s'",
337
                    Json::encode($error)
338
                ));
339
                return false;
340
            }
341
        }
342
343
        return parent::save($query);
344
    }
345
346
    /**
347
     * @param SortableAssociationQueryInterface $query
348
     * @return Objects|null
349
     */
350
    protected function resolveFieldFromQuery(
351
        SortableAssociationQueryInterface $query
352
    ) {
353
        if (null === ($fieldId = $this->resolveStringAttribute($query, 'field'))) {
354
            return null;
355
        }
356
357
        return HubSpot::getInstance()->getObjectsField()->findById($fieldId);
358
    }
359
360
    /**
361
     * @inheritdoc
362
     */
363
    protected static function tableAlias(): string
364
    {
365
        return ObjectAssociation::tableAlias();
366
    }
367
368
    /**
369
     * @inheritdoc
370
     */
371
    public static function recordClass(): string
372
    {
373
        return ObjectAssociation::class;
374
    }
375
}
376