Completed
Push — develop ( f0ef25...431e45 )
by Nate
02:01
created

IntegrationAssociations::getElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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