Completed
Push — develop ( bcbf28...a87a8b )
by Nate
03:33
created

UserRelationship::updateCollection()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 7
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
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\elements\db\UserQuery;
12
use craft\elements\User;
13
use craft\helpers\ArrayHelper;
14
use flipbox\organizations\elements\Organization;
15
use flipbox\organizations\queries\UserAssociationQuery;
16
use flipbox\organizations\records\UserAssociation;
17
use Tightenco\Collect\Support\Collection;
18
19
/**
20
 * Manages Users associated to Organizations
21
 *
22
 * @author Flipbox Factory <[email protected]>
23
 * @since 2.0.0
24
 *
25
 * @method UserAssociation findOrCreate($object)
26
 * @method UserAssociation findOne($object = null)
27
 * @method UserAssociation findOrFail($object)
28
 */
29
class UserRelationship implements RelationshipInterface
30
{
31
    use RelationshipTrait;
32
33
    /**
34
     * @var Organization
35
     */
36
    private $organization;
37
38
    /**
39
     * @param Organization $organization
40
     */
41
    public function __construct(Organization $organization)
42
    {
43
        $this->organization = $organization;
44
    }
45
46
47
    /************************************************************
48
     * COLLECTION
49
     ************************************************************/
50
51
    /**
52
     * Get a collection of associated users
53
     *
54
     * @return User[]|Collection
55
     */
56
    public function getCollection(): Collection
57
    {
58
        if (null === $this->relations) {
59
            return new Collection(
60
                $this->elementQuery()
61
                    ->all()
62
            );
63
        }
64
65
        return $this->getRelationships()
66
            ->sortBy('userOrder')
67
            ->pluck('user');
68
    }
69
70
    /**
71
     * @return Collection
72
     */
73
    protected function existingRelationships(): Collection
74
    {
75
        $relationships = $this->associationQuery()
76
            ->with('types')
77
            ->all();
78
79
        // 'eager' load where we'll pre-populate all of the associations
80
        $elements = $this->elementQuery()
81
            ->id(array_keys($relationships))
82
            ->indexBy('id')
83
            ->all();
84
85
        return $this->createRelations($relationships)
86
            ->transform(function (UserAssociation $association) use ($elements) {
87
                if (isset($elements[$association->getUserId()])) {
88
                    $association->setUser($elements[$association->getUserId()]);
89
                    $association->setOrganization($this->organization);
90
                }
91
                return $association;
92
            });
93
    }
94
95
    /************************************************************
96
     * QUERY
97
     ************************************************************/
98
99
    /**
100
     * @return UserQuery
101
     */
102
    protected function elementQuery(): UserQuery
103
    {
104
        return User::find()
105
            ->organizationId($this->organization->getId() ?: false)
106
            ->anyStatus()
107
            ->limit(null);
108
    }
109
110
    /**
111
     * @return UserAssociationQuery
112
     */
113
    protected function associationQuery(): UserAssociationQuery
114
    {
115
        /** @noinspection PhpUndefinedMethodInspection */
116
        return UserAssociation::find()
117
            ->setOrganizationId($this->organization->getId() ?: false)
0 ignored issues
show
Security Bug introduced by
It seems like $this->organization->getId() ?: false can also be of type false; however, flipbox\organizations\qu...it::setOrganizationId() does only seem to accept string|array<integer,str...nts\Organization>>|null, did you maybe forget to handle an error condition?
Loading history...
118
            ->orderBy([
119
                'organizationOrder' => SORT_ASC
120
            ])
121
            ->limit(null);
122
    }
123
124
    /************************************************************
125
     * CREATE
126
     ************************************************************/
127
128
    /**
129
     * @param $object
130
     * @return UserAssociation
131
     */
132
    protected function create($object): UserAssociation
133
    {
134
        if ($object instanceof UserAssociation) {
135
            return $object;
136
        }
137
138
        return (new UserAssociation())
139
            ->setOrganization($this->organization)
140
            ->setUser($this->resolveObject($object));
141
    }
142
143
144
    /*******************************************
145
     * SAVE
146
     *******************************************/
147
148
    /**
149
     * @inheritDoc
150
     */
151
    protected function delta(): array
152
    {
153
        $existingAssociations = $this->associationQuery()
154
            ->indexBy('userId')
155
            ->all();
156
157
        $associations = [];
158
        $order = 1;
159
160
        /** @var UserAssociation $newAssociation */
161
        foreach ($this->getRelationships() as $newAssociation) {
162
            if (null === ($association = ArrayHelper::remove(
163
                $existingAssociations,
164
                $newAssociation->getUserId()
165
            ))) {
166
                $association = $newAssociation;
167
            } elseif ($newAssociation->getTypes()->isMutated()) {
168
                /** @var UserAssociation $association */
169
                $association->getTypes()->clear()->add(
170
                    $newAssociation->getTypes()->getCollection()
171
                );
172
            }
173
174
            $association->userOrder = $order++;
175
            $association->organizationOrder = $newAssociation->organizationOrder;
176
            $association->state = $newAssociation->state;
177
178
            $association->ignoreSortOrder();
179
180
            $associations[] = $association;
181
        }
182
183
        return [$associations, $existingAssociations];
184
    }
185
186
187
    /*******************************************
188
     * COLLECTION
189
     *******************************************/
190
191
    /**
192
     * @inheritDoc
193
     */
194
    protected function insertCollection(Collection $collection, UserAssociation $association)
195
    {
196
        if ($association->userOrder > 0) {
197
            $collection->splice($association->userOrder - 1, 0, [$association]);
198
            return;
199
        }
200
201
        $collection->push($association);
202
    }
203
204
    /**
205
     * @inheritDoc
206
     */
207
    protected function updateCollection(Collection $collection, UserAssociation $association)
208
    {
209
        if ($key = $this->findKey($association)) {
210
            $collection->offsetUnset($key);
211
        }
212
213
        $this->insertCollection($collection, $association);
214
    }
215
216
217
    /*******************************************
218
     * UTILS
219
     *******************************************/
220
221
    /**
222
     * @param UserAssociation|User|int|array|null $object
223
     * @return int|null
224
     */
225
    protected function findKey($object = null)
226
    {
227
        if ($object instanceof UserAssociation) {
228
            if (!$object->getUser()) {
229
                return null;
230
            }
231
232
            return $this->findRelationshipKey($object->getUser()->email);
233
        }
234
235
        if (null === ($element = $this->resolveObject($object))) {
236
            return null;
237
        }
238
239
        return $this->findRelationshipKey($element->email);
240
    }
241
242
    /**
243
     * @param $identifier
244
     * @return int|string|null
245
     */
246
    protected function findRelationshipKey($identifier)
247
    {
248
        /** @var UserAssociation $association */
249
        foreach ($this->getRelationships()->all() as $key => $association) {
250
            if (null !== $association->getUser() && $association->getUser()->email == $identifier) {
251
                return $key;
252
            }
253
        }
254
255
        return null;
256
    }
257
258
    /**
259
     * @param UserAssociation|User|int|array|null $user
260
     * @return User|null
261
     */
262
    protected function resolveObjectInternal($user)
263
    {
264
        if ($user instanceof UserAssociation) {
265
            return $user->getUser();
266
        }
267
268
        if ($user instanceof User) {
269
            return $user;
270
        }
271
272
        if (is_numeric($user)) {
273
            return \Craft::$app->getUsers()->getUserById($user);
274
        }
275
276
        if (is_string($user)) {
277
            return \Craft::$app->getUsers()->getUserByUsernameOrEmail($user);
278
        }
279
280
        return User::findOne($user);
0 ignored issues
show
Bug Compatibility introduced by
The expression \craft\elements\User::findOne($user); of type craft\base\Element|null|craft\base\Element[] adds the type craft\base\Element[] to the return on line 280 which is incompatible with the return type documented by flipbox\organizations\re...::resolveObjectInternal of type craft\elements\User|null.
Loading history...
281
    }
282
}
283