Completed
Push — develop ( 3644a8...72e19e )
by Nate
06:59
created

ResourceAssociations   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 281
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 11

Test Coverage

Coverage 6.38%

Importance

Changes 0
Metric Value
wmc 32
lcom 2
cbo 11
dl 0
loc 281
ccs 6
cts 94
cp 0.0638
rs 9.84
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 8 1
A findHubSpotIdByElement() 0 5 1
A findHubSpotId() 0 16 3
A findElementId() 0 16 3
A getQuery() 0 4 1
A associationQuery() 0 9 1
A existingAssociations() 0 13 4
A getElementByHubSpotId() 0 11 2
A findElementByHubSpotId() 0 12 2
A findHubSpotIdByElementId() 0 13 2
A query() 0 13 1
A associations() 0 9 1
B save() 0 22 6
A resolveFieldFromQuery() 0 9 2
A tableAlias() 0 4 1
A recordClass() 0 4 1
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\Element;
13
use craft\base\ElementInterface;
14
use craft\errors\ElementNotFoundException;
15
use craft\helpers\Json;
16
use flipbox\craft\sortable\associations\db\SortableAssociationQueryInterface;
17
use flipbox\craft\sortable\associations\records\SortableAssociationInterface;
18
use flipbox\craft\sortable\associations\services\SortableAssociations;
19
use flipbox\ember\services\traits\records\Accessor;
20
use flipbox\ember\validators\MinMaxValidator;
21
use flipbox\hubspot\db\ResourceAssociationQuery;
22
use flipbox\hubspot\fields\Resources;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, flipbox\hubspot\services\Resources.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
23
use flipbox\hubspot\HubSpot;
24
use flipbox\hubspot\records\ResourceAssociation;
25
26
/**
27
 * @author Flipbox Factory <[email protected]>
28
 * @since 1.0.0
29
 *
30
 * @method ResourceAssociationQuery parentGetQuery($config = [])
31
 * @method ResourceAssociation create(array $attributes = [])
32
 * @method ResourceAssociation find($identifier)
33
 * @method ResourceAssociation get($identifier)
34
 * @method ResourceAssociation findByCondition($condition = [])
35
 * @method ResourceAssociation getByCondition($condition = [])
36
 * @method ResourceAssociation findByCriteria($criteria = [])
37
 * @method ResourceAssociation getByCriteria($criteria = [])
38
 * @method ResourceAssociation[] findAllByCondition($condition = [])
39
 * @method ResourceAssociation[] getAllByCondition($condition = [])
40
 * @method ResourceAssociation[] findAllByCriteria($criteria = [])
41
 * @method ResourceAssociation[] getAllByCriteria($criteria = [])
42
 */
43
class ResourceAssociations extends SortableAssociations
44
{
45
    use Accessor {
46
        getQuery as parentGetQuery;
47
    }
48
49
    /**
50
     * @inheritdoc
51
     */
52
    const SOURCE_ATTRIBUTE = ResourceAssociation::SOURCE_ATTRIBUTE;
53
54
    /**
55
     * @inheritdoc
56
     */
57
    const TARGET_ATTRIBUTE = ResourceAssociation::TARGET_ATTRIBUTE;
58
59
    /**
60
     * @inheritdoc
61
     */
62 3
    public function init()
63
    {
64 3
        $settings = HubSpot::getInstance()->getSettings();
65 3
        $this->cacheDuration = $settings->associationsCacheDuration;
66 3
        $this->cacheDependency = $settings->associationsCacheDependency;
67
68 3
        parent::init();
69 3
    }
70
71
    /**
72
     * @param ElementInterface $element
73
     * @param Resources $field
74
     * @return string|null
75
     */
76
    public function findHubSpotIdByElement(ElementInterface $element, Resources $field)
77
    {
78
        /** @var Element $element */
79
        return $this->findHubSpotId($field->id, $element->getId(), $element->siteId);
80
    }
81
82
    /**
83
     * @noinspection PhpDocMissingThrowsInspection
84
     *
85
     * @param string $fieldId
86
     * @param string $elementId
87
     * @param string|null $siteId
88
     * @return null|string
89
     */
90
    public function findHubSpotId(string $fieldId, string $elementId, string $siteId = null)
91
    {
92
        if ($siteId === null) {
93
            /** @noinspection PhpUnhandledExceptionInspection */
94
            $siteId = Craft::$app->getSites()->getCurrentSite()->id;
95
        }
96
97
        $hubSpotId = HubSpot::getInstance()->getResourceAssociations()->getQuery([
98
            'select' => ['hubSpotId'],
99
            'elementId' => $elementId,
100
            'siteId' => $siteId,
101
            'fieldId' => $fieldId
102
        ])->scalar();
103
104
        return is_string($hubSpotId) ? $hubSpotId : null;
105
    }
106
107
    /**
108
     * @noinspection PhpDocMissingThrowsInspection
109
     *
110
     * @param string $fieldId
111
     * @param string $elementId
112
     * @param string|null $siteId
113
     * @return null|string
114
     */
115
    public function findElementId(string $fieldId, string $elementId, string $siteId = null)
116
    {
117
        if ($siteId === null) {
118
            /** @noinspection PhpUnhandledExceptionInspection */
119
            $siteId = Craft::$app->getSites()->getCurrentSite()->id;
120
        }
121
122
        $elementId = HubSpot::getInstance()->getResourceAssociations()->getQuery([
123
            'select' => ['elementId'],
124
            'hubSpotId' => $elementId,
125
            'siteId' => $siteId,
126
            'fieldId' => $fieldId
127
        ])->scalar();
128
129
        return is_string($elementId) ? $elementId : null;
130
    }
131
132
    /**
133
     * @inheritdoc
134
     * @return ResourceAssociationQuery
135
     */
136
    public function getQuery($config = []): SortableAssociationQueryInterface
137
    {
138
        return $this->parentGetQuery($config);
139
    }
140
141
    /**
142
     * @inheritdoc
143
     * @param ResourceAssociation $record
144
     * @return ResourceAssociationQuery
145
     */
146
    protected function associationQuery(
147
        SortableAssociationInterface $record
148
    ): SortableAssociationQueryInterface {
149
        return $this->query(
150
            $record->{static::SOURCE_ATTRIBUTE},
151
            $record->fieldId,
0 ignored issues
show
Bug introduced by
Accessing fieldId on the interface flipbox\craft\sortable\a...bleAssociationInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
152
            $record->siteId
0 ignored issues
show
Bug introduced by
Accessing siteId on the interface flipbox\craft\sortable\a...bleAssociationInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
153
        );
154
    }
155
156
    /**
157
     * @inheritdoc
158
     * @param ResourceAssociationQuery $query
159
     */
160
    protected function existingAssociations(
161
        SortableAssociationQueryInterface $query
162
    ): array {
163
        $source = $this->resolveStringAttribute($query, 'element');
164
        $field = $this->resolveStringAttribute($query, 'field');
165
        $site = $this->resolveStringAttribute($query, 'siteId');
166
167
        if ($source === null || $field === null || $site === null) {
168
            return [];
169
        }
170
171
        return $this->associations($source, $field, $site);
172
    }
173
174
175
    /**
176
     * @param string $hubSpotId
177
     * @return ElementInterface
178
     * @throws ElementNotFoundException
179
     */
180
    public function getElementByHubSpotId(string $hubSpotId): ElementInterface
181
    {
182
        if (!$element = $this->findElementByHubSpotId($hubSpotId)) {
183
            throw new ElementNotFoundException(sprintf(
184
                "Unable to get element from HubSpot Id: '%s'.",
185
                $hubSpotId
186
            ));
187
        }
188
189
        return $element;
190
    }
191
192
    /**
193
     * @param string $hubSpotId
194
     * @return ElementInterface|null
195
     */
196
    public function findElementByHubSpotId(string $hubSpotId)
197
    {
198
        $record = $this->findByCondition([
199
            'objectId' => $hubSpotId
200
        ]);
201
202
        if ($record === null) {
203
            return null;
204
        }
205
206
        return $record->getElement();
207
    }
208
209
    /**
210
     * Find the HubSpot Id by Element Id
211
     *
212
     * @param int $id
213
     * @return string|null
214
     */
215
    public function findHubSpotIdByElementId(int $id)
216
    {
217
        $hubSpotId = $this->getQuery()
218
            ->select(['hubSpotId'])
219
            ->element($id)
220
            ->scalar();
221
222
        if (!$hubSpotId) {
223
            return null;
224
        }
225
226
        return $hubSpotId;
227
    }
228
229
230
    /**
231
     * @param $source
232
     * @param int $fieldId
233
     * @param int $siteId
234
     * @return ResourceAssociationQuery
235
     */
236
    private function query(
237
        $source,
238
        int $fieldId,
239
        int $siteId
240
    ): ResourceAssociationQuery {
241
        return $this->getQuery()
242
            ->where([
243
                static::SOURCE_ATTRIBUTE => $source,
244
                'fieldId' => $fieldId,
245
                'siteId' => $siteId
246
            ])
247
            ->orderBy(['sortOrder' => SORT_ASC]);
248
    }
249
250
    /**
251
     * @param $source
252
     * @param int $fieldId
253
     * @param int $siteId
254
     * @return array
255
     */
256
    private function associations(
257
        $source,
258
        int $fieldId,
259
        int $siteId
260
    ): array {
261
        return $this->query($source, $fieldId, $siteId)
262
            ->indexBy(static::TARGET_ATTRIBUTE)
263
            ->all();
264
    }
265
266
    /**
267
     * @inheritdoc
268
     * @param bool $validate
269
     * @throws \Exception
270
     */
271
    public function save(
272
        SortableAssociationQueryInterface $query,
273
        bool $validate = true
274
    ): bool {
275
        if ($validate === true && null !== ($field = $this->resolveFieldFromQuery($query))) {
276
            $error = '';
277
            (new MinMaxValidator([
278
                'min' => $field->min ? (int)$field->min : null,
279
                'max' => $field->max ? (int)$field->max : null
280
            ]))->validate($query, $error);
281
282
            if (!empty($error)) {
283
                HubSpot::error(sprintf(
284
                    "Hubspot Resource failed to save due to the following validation errors: '%s'",
285
                    Json::encode($error)
286
                ));
287
                return false;
288
            }
289
        }
290
291
        return parent::save($query);
292
    }
293
294
    /**
295
     * @param SortableAssociationQueryInterface $query
296
     * @return Resources|null
297
     */
298
    protected function resolveFieldFromQuery(
299
        SortableAssociationQueryInterface $query
300
    ) {
301
        if (null === ($fieldId = $this->resolveStringAttribute($query, 'field'))) {
302
            return null;
303
        }
304
305
        return HubSpot::getInstance()->getResourcesField()->findById($fieldId);
306
    }
307
308
    /**
309
     * @inheritdoc
310
     */
311
    protected static function tableAlias(): string
312
    {
313
        return ResourceAssociation::tableAlias();
314
    }
315
316
    /**
317
     * @inheritdoc
318
     */
319
    public static function recordClass(): string
320
    {
321
        return ResourceAssociation::class;
322
    }
323
}
324