Completed
Push — master ( 136153...d5a3eb )
by Nate
19:29 queued 17:38
created

ObjectsField::getObjects()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 5
cp 0
rs 9.7
c 0
b 0
f 0
cc 1
nc 1
nop 0
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 Craft;
12
use craft\base\ElementInterface;
13
use craft\base\FieldInterface;
14
use craft\helpers\Component as ComponentHelper;
15
use craft\helpers\StringHelper;
16
use flipbox\craft\sortable\associations\db\SortableAssociationQueryInterface;
17
use flipbox\craft\sortable\associations\records\SortableAssociationInterface;
18
use flipbox\craft\sortable\associations\services\SortableFields;
19
use flipbox\hubspot\db\ObjectAssociationQuery;
20
use flipbox\hubspot\events\RegisterResourceFieldActionsEvent;
21
use flipbox\hubspot\fields\actions\ObjectActionInterface;
22
use flipbox\hubspot\fields\actions\ObjectItemActionInterface;
23
use flipbox\hubspot\fields\actions\SyncItemFrom;
24
use flipbox\hubspot\fields\actions\SyncItemTo;
25
use flipbox\hubspot\fields\actions\SyncTo;
26
use flipbox\hubspot\fields\Objects;
27
use flipbox\hubspot\HubSpot;
28
use flipbox\hubspot\records\ObjectAssociation;
29
use flipbox\hubspot\web\assets\objects\Objects as ObjectsFieldAsset;
30
use yii\base\Exception;
31
32
/**
33
 * @author Flipbox Factory <[email protected]>
34
 * @since 1.0.0
35
 */
36
class ObjectsField extends SortableFields
37
{
38
    /**
39
     * @inheritdoc
40
     */
41
    const SOURCE_ATTRIBUTE = ObjectAssociation::SOURCE_ATTRIBUTE;
42
43
    /**
44
     * @inheritdoc
45
     */
46
    const TARGET_ATTRIBUTE = ObjectAssociation::TARGET_ATTRIBUTE;
47
48
    /**
49
     * HubSpot Object Association fields, indexed by their Id.
50
     *
51
     * @var Objects[]
52
     */
53
    private $fields = [];
54
55
    /**
56
     * @inheritdoc
57
     */
58
    protected static function tableAlias(): string
59
    {
60
        return ObjectAssociation::tableAlias();
61
    }
62
63
    /**
64
     * @param int $id
65
     * @return Objects|null
66
     */
67
    public function findById(int $id)
68
    {
69
        if (!array_key_exists($id, $this->fields)) {
70
            $field = Craft::$app->getFields()->getFieldById($id);
71
            if (!$field instanceof Objects) {
72
                $field = null;
73
            }
74
75
            $this->fields[$id] = $field;
76
        }
77
78
        return $this->fields[$id];
79
    }
80
81
    /**
82
     * @inheritdoc
83
     * @return ObjectAssociationQuery
84
     * @throws Exception
85
     */
86
    protected function getQuery(
87
        FieldInterface $field,
88
        ElementInterface $element = null
89
    ): SortableAssociationQueryInterface {
90
        $query = $this->baseQuery($field, $element);
91
92
        /** @var Objects $field */
93
94
        if ($field->max !== null) {
95
            $query->limit($field->max);
96
        }
97
98
        return $query;
99
    }
100
101
    /**
102
     * @param FieldInterface $field
103
     * @param ElementInterface|null $element
104
     * @return ObjectAssociationQuery
105
     * @throws Exception
106
     */
107
    private function baseQuery(
108
        FieldInterface $field,
109
        ElementInterface $element = null
110
    ): ObjectAssociationQuery {
111
        /** @var Objects $field */
112
        $this->ensureField($field);
113
114
        $query = HubSpot::getInstance()->getObjectAssociations()->getQuery()
115
            ->field($field->id)
116
            ->site($this->targetSiteId($element));
117
118
        $query->{ObjectAssociation::SOURCE_ATTRIBUTE} = $element === null ? null : $element->getId();
119
120
        return $query;
121
    }
122
123
    /*******************************************
124
     * NORMALIZE VALUE
125
     *******************************************/
126
127
    /**
128
     * @inheritdoc
129
     * @throws Exception
130
     */
131
    protected function normalizeQueryInputValue(
132
        FieldInterface $field,
133
        $value,
134
        int &$sortOrder,
135
        ElementInterface $element = null
136
    ): SortableAssociationInterface {
137
        if (is_array($value)) {
138
            $value = StringHelper::toString($value);
139
        }
140
141
        $query = $this->baseQuery($field, $element)
142
            ->sortOrder($sortOrder++);
143
144
        $query->{ObjectAssociation::TARGET_ATTRIBUTE} = $value;
145
146
        return $query;
147
    }
148
149
    /**
150
     * @param FieldInterface $field
151
     * @throws Exception
152
     */
153
    private function ensureField(FieldInterface $field)
154
    {
155
        if (!$field instanceof Objects) {
156
            throw new Exception(sprintf(
157
                "The field must be an instance of '%s', '%s' given.",
158
                (string)Objects::class,
159
                (string)get_class($field)
160
            ));
161
        }
162
    }
163
164
165
    /**
166
     * @param Objects $field
167
     * @param ObjectAssociationQuery $query
168
     * @param ElementInterface|null $element
169
     * @param bool $static
170
     * @return null|string
171
     * @throws Exception
172
     * @throws \Twig_Error_Loader
173
     */
174
    public function getInputHtml(
175
        Objects $field,
176
        ObjectAssociationQuery $query,
177
        ElementInterface $element = null,
178
        bool $static = false
179
    ) {
180
        Craft::$app->getView()->registerAssetBundle(ObjectsFieldAsset::class);
181
182
        return Craft::$app->getView()->renderTemplate(
183
            $field::INPUT_TEMPLATE_PATH,
184
            [
185
                'field' => $field,
186
                'element' => $element,
187
                'value' => $query,
188
                'objectLabel' => $this->getObjectLabel($field),
189
                'actions' => $this->getActionHtml($field, $element),
190
                'itemActions' => $this->getItemActionHtml($field, $element),
191
                'static' => $static
192
            ]
193
        );
194
    }
195
196
    /**
197
     * @param Objects $field
198
     * @return null|string
199
     * @throws Exception
200
     * @throws \Twig_Error_Loader
201
     */
202
    public function getSettingsHtml(
203
        Objects $field
204
    ) {
205
        return Craft::$app->getView()->renderTemplate(
206
            'hubspot/_components/fieldtypes/Objects/settings',
207
            [
208
                'field' => $field,
209
                'objects' => $this->getObjects(),
210
                'availableActions' => $this->getAvailableActions($field),
211
                'availableItemActions' => $this->getAvailableItemActions($field)
212
            ]
213
        );
214
    }
215
216
    /*******************************************
217
     * RESOURCES
218
     *******************************************/
219
220
    /**
221
     * @return array
222
     */
223
    protected function getObjects(): array
224
    {
225
        return [
226
            resources\Companies::HUBSPOT_RESOURCE => [
227
                'label' => Craft::t('hubspot', 'Companies'),
228
                'value' => resources\Companies::HUBSPOT_RESOURCE
229
            ],
230
            resources\Contacts::HUBSPOT_RESOURCE => [
231
                'label' => Craft::t('hubspot', 'Contacts'),
232
                'value' => resources\Contacts::HUBSPOT_RESOURCE
233
            ],
234
            resources\ContactLists::HUBSPOT_RESOURCE => [
235
                'label' => Craft::t('hubspot', 'Contact Lists'),
236
                'value' => resources\ContactLists::HUBSPOT_RESOURCE
237
            ]
238
        ];
239
    }
240
241
    /**
242
     * @param Objects $field
243
     * @return null
244
     */
245
    protected function getObjectLabel(Objects $field)
246
    {
247
        return $this->getObjects()[$field->object]['label'] ?? null;
248
    }
249
250
    /*******************************************
251
     * ACTIONS
252
     *******************************************/
253
254
    /**
255
     * @param Objects $field
256
     * @return ObjectActionInterface[]
257
     * @throws \craft\errors\MissingComponentException
258
     * @throws \yii\base\InvalidConfigException
259
     */
260
    public function getAvailableActions(Objects $field): array
261
    {
262
        $event = new RegisterResourceFieldActionsEvent([
263
            'actions' => [
264
                SyncTo::class
265
            ]
266
        ]);
267
268
        $field->trigger(
269
            $field::EVENT_REGISTER_AVAILABLE_ACTIONS,
270
            $event
271
        );
272
        return $this->resolveActions($event->actions, ObjectActionInterface::class);
273
    }
274
275
    /**
276
     * @param Objects $field
277
     * @param ElementInterface|null $element
278
     * @return ObjectActionInterface[]
279
     * @throws \craft\errors\MissingComponentException
280
     * @throws \yii\base\InvalidConfigException
281
     */
282
    public function getActions(Objects $field, ElementInterface $element = null): array
283
    {
284
        $event = new RegisterResourceFieldActionsEvent([
285
            'actions' => $field->selectedActions,
286
            'element' => $element
287
        ]);
288
289
        $field->trigger(
290
            $field::EVENT_REGISTER_ACTIONS,
291
            $event
292
        );
293
294
        return $this->resolveActions($event->actions, ObjectActionInterface::class);
295
    }
296
297
    /**
298
     * @param Objects $field
299
     * @return ObjectActionInterface[]
300
     * @throws \craft\errors\MissingComponentException
301
     * @throws \yii\base\InvalidConfigException
302
     */
303
    public function getAvailableItemActions(Objects $field): array
304
    {
305
        $event = new RegisterResourceFieldActionsEvent([
306
            'actions' => [
307
                SyncItemFrom::class,
308
                SyncItemTo::class,
309
            ]
310
        ]);
311
312
        $field->trigger(
313
            $field::EVENT_REGISTER_AVAILABLE_ITEM_ACTIONS,
314
            $event
315
        );
316
317
        return $this->resolveActions($event->actions, ObjectItemActionInterface::class);
318
    }
319
320
    /**
321
     * @param Objects $field
322
     * @param ElementInterface|null $element
323
     * @return ObjectItemActionInterface[]
324
     * @throws \craft\errors\MissingComponentException
325
     * @throws \yii\base\InvalidConfigException
326
     */
327
    public function getItemActions(Objects $field, ElementInterface $element = null): array
328
    {
329
        $event = new RegisterResourceFieldActionsEvent([
330
            'actions' => $field->selectedItemActions,
331
            'element' => $element
332
        ]);
333
334
        $field->trigger(
335
            $field::EVENT_REGISTER_ITEM_ACTIONS,
336
            $event
337
        );
338
339
        return $this->resolveActions($event->actions, ObjectItemActionInterface::class);
340
    }
341
342
    /**
343
     * @param array $actions
344
     * @param string $instance
345
     * @return array
346
     * @throws \craft\errors\MissingComponentException
347
     * @throws \yii\base\InvalidConfigException
348
     */
349
    protected function resolveActions(array $actions, string $instance)
350
    {
351
        foreach ($actions as $i => $action) {
352
            // $action could be a string or config array
353
            if (!$action instanceof $instance) {
354
                $actions[$i] = $action = ComponentHelper::createComponent($action, $instance);
355
356
                if ($actions[$i] === null) {
357
                    unset($actions[$i]);
358
                }
359
            }
360
        }
361
362
        return array_values($actions);
363
    }
364
365
    /**
366
     * @param Objects $field
367
     * @param ElementInterface|null $element
368
     * @return array
369
     * @throws \craft\errors\MissingComponentException
370
     * @throws \yii\base\InvalidConfigException
371
     */
372
    protected function getActionHtml(Objects $field, ElementInterface $element = null): array
373
    {
374
        $actionData = [];
375
376
        foreach ($this->getActions($field, $element) as $action) {
377
            $actionData[] = [
378
                'type' => get_class($action),
379
                'destructive' => $action->isDestructive(),
380
                'params' => [],
381
                'name' => $action->getTriggerLabel(),
382
                'trigger' => $action->getTriggerHtml(),
383
                'confirm' => $action->getConfirmationMessage(),
384
            ];
385
        }
386
387
        return $actionData;
388
    }
389
390
    /**
391
     * @param Objects $field
392
     * @param ElementInterface|null $element
393
     * @return array
394
     * @throws \craft\errors\MissingComponentException
395
     * @throws \yii\base\InvalidConfigException
396
     */
397
    protected function getItemActionHtml(Objects $field, ElementInterface $element = null): array
398
    {
399
        $actionData = [];
400
401
        foreach ($this->getItemActions($field, $element) as $action) {
402
            $actionData[] = [
403
                'type' => get_class($action),
404
                'destructive' => $action->isDestructive(),
405
                'params' => [],
406
                'name' => $action->getTriggerLabel(),
407
                'trigger' => $action->getTriggerHtml(),
408
                'confirm' => $action->getConfirmationMessage(),
409
            ];
410
        }
411
412
        return $actionData;
413
    }
414
}
415