Issues (55)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/relationships/UserTypeRelationship.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/organization/license
6
 * @link       https://www.flipboxfactory.com/software/organization/
7
 */
8
9
namespace flipbox\organizations\relationships;
10
11
use craft\helpers\ArrayHelper;
12
use craft\helpers\Json;
13
use flipbox\craft\ember\helpers\QueryHelper;
14
use flipbox\organizations\Organizations;
15
use flipbox\organizations\queries\UserTypeAssociationQuery;
16
use flipbox\organizations\records\OrganizationType;
17
use flipbox\organizations\records\OrganizationTypeAssociation;
18
use flipbox\organizations\records\UserAssociation;
19
use flipbox\organizations\records\UserType;
20
use flipbox\organizations\records\UserTypeAssociation;
21
use Tightenco\Collect\Support\Collection;
22
23
/**
24
 * Manages User Types associated to Organization/User associations
25
 *
26
 * @author Flipbox Factory <[email protected]>
27
 * @since 2.0.0
28
 *
29
 * @property UserTypeAssociation[] $associations
30
 *
31
 * @method UserTypeAssociation findOrCreate($object)
32
 * @method UserTypeAssociation findOne($object = null)
33
 * @method UserTypeAssociation findOrFail($object)
34
 */
35
class UserTypeRelationship implements RelationshipInterface
36
{
37
    use RelationshipTrait {
38
        reset as parentReset;
39
        newRelations as parentSetCache;
40
        addToRelations as parentAddToCache;
41
        removeFromRelations as parentRemoveFromCache;
42
    }
43
44
    /**
45
     * @var UserAssociation
46
     */
47
    private $association;
48
49
    /**
50
     * @param UserAssociation $association
51
     */
52
    public function __construct(UserAssociation $association)
53
    {
54
        $this->association = $association;
55
    }
56
57
58
    /************************************************************
59
     * COLLECTION
60
     ************************************************************/
61
62
    /**
63
     * Get a collection of associated organizations
64
     *
65
     * @return Collection
66
     */
67
    public function getCollection(): Collection
68
    {
69
        return $this->getRelationships()
70
            ->pluck('type');
71
    }
72
73
    /**
74
     * @return Collection
75
     */
76
    protected function existingRelationships(): Collection
77
    {
78
        return $this->createRelations(
79
            $this->query()
80
                ->with('typeRecord')
81
                ->all()
82
        );
83
    }
84
85
    /************************************************************
86
     * QUERY
87
     ************************************************************/
88
89
    /**
90
     * @inheritDoc
91
     * @return UserTypeAssociationQuery
92
     */
93
    private function query(): UserTypeAssociationQuery
94
    {
95
        return UserTypeAssociation::find()
96
            ->setUserId($this->association->getId() ?: false)
97
            ->orderBy([
98
                'sortOrder' => SORT_ASC
99
            ])
100
            ->limit(null);
101
    }
102
103
    /**
104
     * @param UserTypeAssociation|UserType|int|string $type
105
     * @return UserTypeAssociation
106
     */
107
    protected function create($type): UserTypeAssociation
108
    {
109
        if ($type instanceof UserTypeAssociation) {
110
            return $type;
111
        }
112
113
        $association = (new UserTypeAssociation())
114
            ->setType($this->resolveObject($type));
115
116
        $association->userId = $this->association->id;
117
118
        return $association;
119
    }
120
121
    /**
122
     * Reset associations
123
     */
124
    public function reset(): RelationshipInterface
125
    {
126
        unset($this->association->typeRecords);
127
        return $this->parentReset();
128
    }
129
130
131
    /*******************************************
132
     * SAVE
133
     *******************************************/
134
135
    /**
136
     * @inheritDoc
137
     */
138
    protected function delta(): array
139
    {
140
        $existingAssociations = $this->query()
141
            ->indexBy('typeId')
142
            ->all();
143
144
        $associations = [];
145
        $order = 1;
146
147
        /** @var UserTypeAssociation $newAssociation */
148
        foreach ($this->getRelationships() as $newAssociation) {
149
            $association = ArrayHelper::remove(
150
                $existingAssociations,
151
                $newAssociation->getTypeId()
152
            );
153
154
            $newAssociation->sortOrder = $order++;
155
156
            /** @var UserTypeAssociation $association */
157
            $association = $association ?: $newAssociation;
158
159
            // Has anything changed?
160
            if (!$association->getIsNewRecord() && !$this->hasChanged($newAssociation, $association)) {
161
                continue;
162
            }
163
164
            $associations[] = $this->sync($association, $newAssociation);
165
        }
166
167
        return [$associations, $existingAssociations];
168
    }
169
170
    /**
171
     * @param UserTypeAssociation $new
172
     * @param UserTypeAssociation $existing
173
     * @return bool
174
     */
175
    private function hasChanged(UserTypeAssociation $new, UserTypeAssociation $existing): bool
176
    {
177
        return $new->sortOrder != $existing->sortOrder;
178
    }
179
180
    /**
181
     * @param UserTypeAssociation $from
182
     * @param UserTypeAssociation $to
183
     *
184
     * @return UserTypeAssociation
185
     */
186
    private function sync(
187
        UserTypeAssociation $to,
188
        UserTypeAssociation $from
189
    ): UserTypeAssociation {
190
        $to->sortOrder = $from->sortOrder;
191
192
        $to->ignoreSortOrder();
193
194
        return $to;
195
    }
196
197
    /*******************************************
198
     * COLLECTION UTILS
199
     *******************************************/
200
201
    /**
202
     * @inheritDoc
203
     */
204
    protected function insertCollection(Collection $collection, UserTypeAssociation $association)
205
    {
206
        if ($association->sortOrder > 0) {
207
            $collection->splice($association->sortOrder - 1, 0, [$association]);
208
            return;
209
        }
210
211
        $collection->push($association);
212
    }
213
214
    /**
215
     * @inheritDoc
216
     */
217
    protected function updateCollection(Collection $collection, UserAssociation $association)
218
    {
219
        if (null !== ($key = $this->findKey($association))) {
0 ignored issues
show
$association is of type object<flipbox\organizat...ecords\UserAssociation>, but the function expects a object<flipbox\organizat...ype>|integer|array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
220
            $collection->offsetUnset($key);
221
        }
222
223
        $this->insertCollection($collection, $association);
0 ignored issues
show
$association is of type object<flipbox\organizat...ecords\UserAssociation>, but the function expects a object<flipbox\organizat...ds\UserTypeAssociation>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
224
    }
225
226
227
    /*******************************************
228
     * CACHE
229
     *******************************************/
230
231
    /**
232
     * @param array $associations
233
     * @return static
234
     */
235
    protected function newRelations(array $associations): self
236
    {
237
        $this->parentSetCache($associations);
238
        $this->syncToRelations();
239
240
        return $this;
241
    }
242
243
    /**
244
     * @param $association
245
     * @return static
246
     */
247
    protected function addToRelations($association): self
248
    {
249
        $this->parentAddToCache($association);
250
        $this->syncToRelations();
251
252
        return $this;
253
    }
254
255
    /**
256
     * @param int $key
257
     * @return static
258
     */
259
    protected function removeFromRelations(int $key): self
260
    {
261
        $this->parentRemoveFromCache($key);
262
        $this->syncToRelations();
263
264
        return $this;
265
    }
266
267
    /*******************************************
268
     * UTILS
269
     *******************************************/
270
271
    /**
272
     * @return $this
273
     */
274
    private function syncToRelations()
275
    {
276
        $this->association->populateRelation(
277
            'typeRecords',
278
            $this->getRelationships()->pluck('type')->all()
279
        );
280
        return $this;
281
    }
282
283
    /**
284
     * @param UserTypeAssociation|UserType|int|array|null $object
285
     * @return int|null
286
     */
287
    protected function findKey($object = null)
288
    {
289
        if ($object instanceof UserTypeAssociation) {
290
            return $this->findRelationshipKey($object->getTypeId());
291
        }
292
293
        if (null === ($type = $this->resolveObject($object))) {
294
            return null;
295
        }
296
297
        return $this->findRelationshipKey($type->id);
298
    }
299
300
    /**
301
     * @param $identifier
302
     * @return int|string|null
303
     */
304
    private function findRelationshipKey($identifier)
305
    {
306
        if (null === $identifier) {
307
            return null;
308
        }
309
310
        /** @var UserTypeAssociation $association */
311
        foreach ($this->getRelationships()->all() as $key => $association) {
312
            if ($association->getTypeId() == $identifier) {
313
                return $key;
314
            }
315
        }
316
317
        return null;
318
    }
319
320
    /**
321
     * @param UserTypeAssociation|UserType|int|array|null $type
322
     * @return UserType|null
323
     */
324
    protected function resolveObjectInternal($type)
325
    {
326
        if ($type instanceof UserTypeAssociation) {
327
            return $type->getType();
328
        }
329
330
        if ($type instanceof UserType) {
331
            return $type;
332
        }
333
334
        return UserType::findOne($type);
335
    }
336
}
337