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

ObjectsField::getAvailableItemActions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 7
cp 0
rs 9.7333
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
                'availableActions' => $this->getAvailableActions($field),
208
                'availableItemActions' => $this->getAvailableItemActions($field)
209
            ]
210
        );
211
    }
212
213
214
    /*******************************************
215
     * ACTIONS
216
     *******************************************/
217
218
    /**
219
     * @param Objects $field
220
     * @return ObjectActionInterface[]
221
     * @throws \craft\errors\MissingComponentException
222
     * @throws \yii\base\InvalidConfigException
223
     */
224
    public function getAvailableActions(Objects $field): array
225
    {
226
        $event = new RegisterResourceFieldActionsEvent([
227
            'actions' => []
228
        ]);
229
230
        $field->trigger(
231
            $field::EVENT_REGISTER_AVAILABLE_ACTIONS,
232
            $event
233
        );
234
        return $this->resolveActions($event->actions, ObjectActionInterface::class);
235
    }
236
237
    /**
238
     * @param Objects $field
239
     * @param ElementInterface|null $element
240
     * @return ObjectActionInterface[]
241
     * @throws \craft\errors\MissingComponentException
242
     * @throws \yii\base\InvalidConfigException
243
     */
244
    public function getActions(Objects $field, ElementInterface $element = null): array
245
    {
246
        $event = new RegisterResourceFieldActionsEvent([
247
            'actions' => $field->selectedActions,
248
            'element' => $element
249
        ]);
250
251
        $field->trigger(
252
            $field::EVENT_REGISTER_ACTIONS,
253
            $event
254
        );
255
256
        return $this->resolveActions($event->actions, ObjectActionInterface::class);
257
    }
258
259
    /**
260
     * @param Objects $field
261
     * @return ObjectActionInterface[]
262
     * @throws \craft\errors\MissingComponentException
263
     * @throws \yii\base\InvalidConfigException
264
     */
265
    public function getAvailableItemActions(Objects $field): array
266
    {
267
        $event = new RegisterResourceFieldActionsEvent([
268
            'actions' => [
269
                SyncItemFrom::class,
270
                SyncItemTo::class,
271
            ]
272
        ]);
273
274
        $field->trigger(
275
            $field::EVENT_REGISTER_AVAILABLE_ITEM_ACTIONS,
276
            $event
277
        );
278
279
        return $this->resolveActions($event->actions, ObjectItemActionInterface::class);
280
    }
281
282
    /**
283
     * @param Objects $field
284
     * @param ElementInterface|null $element
285
     * @return ObjectItemActionInterface[]
286
     * @throws \craft\errors\MissingComponentException
287
     * @throws \yii\base\InvalidConfigException
288
     */
289
    public function getItemActions(Objects $field, ElementInterface $element = null): array
290
    {
291
        $event = new RegisterResourceFieldActionsEvent([
292
            'actions' => $field->selectedItemActions,
293
            'element' => $element
294
        ]);
295
296
        $field->trigger(
297
            $field::EVENT_REGISTER_ITEM_ACTIONS,
298
            $event
299
        );
300
301
        return $this->resolveActions($event->actions, ObjectItemActionInterface::class);
302
    }
303
304
    /**
305
     * @param array $actions
306
     * @param string $instance
307
     * @return array
308
     * @throws \craft\errors\MissingComponentException
309
     * @throws \yii\base\InvalidConfigException
310
     */
311
    protected function resolveActions(array $actions, string $instance)
312
    {
313
        foreach ($actions as $i => $action) {
314
            // $action could be a string or config array
315
            if (!$action instanceof $instance) {
316
                $actions[$i] = $action = ComponentHelper::createComponent($action, $instance);
317
318
                if ($actions[$i] === null) {
319
                    unset($actions[$i]);
320
                }
321
            }
322
        }
323
324
        return array_values($actions);
325
    }
326
327
    /**
328
     * @param Objects $field
329
     * @param ElementInterface|null $element
330
     * @return array
331
     * @throws \craft\errors\MissingComponentException
332
     * @throws \yii\base\InvalidConfigException
333
     */
334
    protected function getActionHtml(Objects $field, ElementInterface $element = null): array
335
    {
336
        $actionData = [];
337
338
        foreach ($this->getActions($field, $element) as $action) {
339
            $actionData[] = [
340
                'type' => get_class($action),
341
                'destructive' => $action->isDestructive(),
342
                'params' => [],
343
                'name' => $action->getTriggerLabel(),
344
                'trigger' => $action->getTriggerHtml(),
345
                'confirm' => $action->getConfirmationMessage(),
346
            ];
347
        }
348
349
        return $actionData;
350
    }
351
352
    /**
353
     * @param Objects $field
354
     * @param ElementInterface|null $element
355
     * @return array
356
     * @throws \craft\errors\MissingComponentException
357
     * @throws \yii\base\InvalidConfigException
358
     */
359
    protected function getItemActionHtml(Objects $field, ElementInterface $element = null): array
360
    {
361
        $actionData = [];
362
363
        foreach ($this->getItemActions($field, $element) as $action) {
364
            $actionData[] = [
365
                'type' => get_class($action),
366
                'destructive' => $action->isDestructive(),
367
                'params' => [],
368
                'name' => $action->getTriggerLabel(),
369
                'trigger' => $action->getTriggerHtml(),
370
                'confirm' => $action->getConfirmationMessage(),
371
            ];
372
        }
373
374
        return $actionData;
375
    }
376
}
377