Completed
Push — develop ( f37ae4...1d947e )
by Nate
18:30
created

ResourceAssociations::save()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 20
cp 0
rs 8.9457
c 0
b 0
f 0
cc 6
nc 3
nop 2
crap 42
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\base\ElementInterface;
12
use craft\errors\ElementNotFoundException;
13
use craft\helpers\Json;
14
use flipbox\hubspot\db\ResourceAssociationQuery;
15
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...
16
use flipbox\hubspot\HubSpot;
17
use flipbox\hubspot\records\ResourceAssociation;
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\services\traits\records\Accessor;
22
use flipbox\ember\validators\MinMaxValidator;
23
24
/**
25
 * @author Flipbox Factory <[email protected]>
26
 * @since 1.0.0
27
 *
28
 * @method ResourceAssociationQuery parentGetQuery($config = [])
29
 * @method ResourceAssociation create(array $attributes = [])
30
 * @method ResourceAssociation find($identifier)
31
 * @method ResourceAssociation get($identifier)
32
 * @method ResourceAssociation findByCondition($condition = [])
33
 * @method ResourceAssociation getByCondition($condition = [])
34
 * @method ResourceAssociation findByCriteria($criteria = [])
35
 * @method ResourceAssociation getByCriteria($criteria = [])
36
 * @method ResourceAssociation[] findAllByCondition($condition = [])
37
 * @method ResourceAssociation[] getAllByCondition($condition = [])
38
 * @method ResourceAssociation[] findAllByCriteria($criteria = [])
39
 * @method ResourceAssociation[] getAllByCriteria($criteria = [])
40
 */
41
class ResourceAssociations extends SortableAssociations
42
{
43
    use Accessor {
44
        getQuery as parentGetQuery;
45
    }
46
47
    /**
48
     * @inheritdoc
49
     */
50
    const SOURCE_ATTRIBUTE = ResourceAssociation::SOURCE_ATTRIBUTE;
51
52
    /**
53
     * @inheritdoc
54
     */
55
    const TARGET_ATTRIBUTE = ResourceAssociation::TARGET_ATTRIBUTE;
56
57
    /**
58
     * @inheritdoc
59
     */
60
    public function init()
61
    {
62
        $settings = HubSpot::getInstance()->getSettings();
63
        $this->cacheDuration = $settings->associationsCacheDuration;
64
        $this->cacheDependency = $settings->associationsCacheDependency;
65
66
        parent::init();
67
    }
68
69
    /**
70
     * @inheritdoc
71
     * @return ResourceAssociationQuery
72
     */
73
    public function getQuery($config = []): SortableAssociationQueryInterface
74
    {
75
        return $this->parentGetQuery($config);
76
    }
77
78
    /**
79
     * @inheritdoc
80
     * @param ResourceAssociation $record
81
     * @return ResourceAssociationQuery
82
     */
83
    protected function associationQuery(
84
        SortableAssociationInterface $record
85
    ): SortableAssociationQueryInterface {
86
        return $this->query(
87
            $record->{static::SOURCE_ATTRIBUTE},
88
            $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...
89
            $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...
90
        );
91
    }
92
93
    /**
94
     * @inheritdoc
95
     * @param ResourceAssociationQuery $query
96
     */
97
    protected function existingAssociations(
98
        SortableAssociationQueryInterface $query
99
    ): array {
100
        $source = $this->resolveStringAttribute($query, 'element');
101
        $field = $this->resolveStringAttribute($query, 'field');
102
        $site = $this->resolveStringAttribute($query, 'siteId');
103
104
        if ($source === null || $field === null || $site === null) {
105
            return [];
106
        }
107
108
        return $this->associations($source, $field, $site);
109
    }
110
111
112
    /**
113
     * @param string $hubSpotId
114
     * @return ElementInterface
115
     * @throws ElementNotFoundException
116
     */
117
    public function getElementByHubSpotId(string $hubSpotId): ElementInterface
118
    {
119
        if (!$element = $this->findElementByHubSpotId($hubSpotId)) {
120
            throw new ElementNotFoundException(sprintf(
121
                "Unable to get element from HubSpot Id: '%s'.",
122
                $hubSpotId
123
            ));
124
        }
125
126
        return $element;
127
    }
128
129
    /**
130
     * @param string $hubSpotId
131
     * @return ElementInterface|null
132
     */
133
    public function findElementByHubSpotId(string $hubSpotId)
134
    {
135
        $record = $this->findByCondition([
136
            'objectId' => $hubSpotId
137
        ]);
138
139
        if ($record === null) {
140
            return null;
141
        }
142
143
        return $record->getElement();
144
    }
145
146
    /**
147
     * Find the HubSpot Id by Element Id
148
     *
149
     * @param int $id
150
     * @return string|null
151
     */
152
    public function findHubSpotIdByElementId(int $id)
153
    {
154
        $hubSpotId = $this->getQuery()
155
            ->select(['hubSpotId'])
156
            ->element($id)
157
            ->scalar();
158
159
        if (!$hubSpotId) {
160
            return null;
161
        }
162
163
        return $hubSpotId;
164
    }
165
166
167
    /**
168
     * @param $source
169
     * @param int $fieldId
170
     * @param int $siteId
171
     * @return ResourceAssociationQuery
172
     */
173
    private function query(
174
        $source,
175
        int $fieldId,
176
        int $siteId
177
    ): ResourceAssociationQuery {
178
        return $this->getQuery()
179
            ->where([
180
                static::SOURCE_ATTRIBUTE => $source,
181
                'fieldId' => $fieldId,
182
                'siteId' => $siteId
183
            ])
184
            ->orderBy(['sortOrder' => SORT_ASC]);
185
    }
186
187
    /**
188
     * @param $source
189
     * @param int $fieldId
190
     * @param int $siteId
191
     * @return array
192
     */
193
    private function associations(
194
        $source,
195
        int $fieldId,
196
        int $siteId
197
    ): array {
198
        return $this->query($source, $fieldId, $siteId)
199
            ->indexBy(static::TARGET_ATTRIBUTE)
200
            ->all();
201
    }
202
203
    /**
204
     * @inheritdoc
205
     * @param bool $validate
206
     * @throws \Exception
207
     */
208
    public function save(
209
        SortableAssociationQueryInterface $query,
210
        bool $validate = true
211
    ): bool {
212
        if ($validate === true && null !== ($field = $this->resolveFieldFromQuery($query))) {
213
            $error = '';
214
            (new MinMaxValidator([
215
                'min' => $field->min ? (int)$field->min : null,
216
                'max' => $field->max ? (int)$field->max : null
217
            ]))->validate($query, $error);
218
219
            if (!empty($error)) {
220
                HubSpot::error(sprintf(
221
                    "Hubspot Resource failed to save due to the following validation errors: '%s'",
222
                    Json::encode($error)
223
                ));
224
                return false;
225
            }
226
        }
227
228
        return parent::save($query);
229
    }
230
231
    /**
232
     * @param SortableAssociationQueryInterface $query
233
     * @return Resources|null
234
     */
235
    protected function resolveFieldFromQuery(
236
        SortableAssociationQueryInterface $query
237
    ) {
238
        if (null === ($fieldId = $this->resolveStringAttribute($query, 'field'))) {
239
            return null;
240
        }
241
242
        return HubSpot::getInstance()->getResourcesField()->findById($fieldId);
243
    }
244
245
    /**
246
     * @inheritdoc
247
     */
248
    protected static function tableAlias(): string
249
    {
250
        return ResourceAssociation::tableAlias();
251
    }
252
253
    /**
254
     * @inheritdoc
255
     */
256
    public static function recordClass(): string
257
    {
258
        return ResourceAssociation::class;
259
    }
260
}
261