Completed
Push — develop ( 136153...525928 )
by Nate
03:34
created

ObjectsField::getSettingsHtml()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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