Completed
Push — master ( b7e6d7...fe783a )
by Nate
10:27 queued 08:34
created

Organizations::associations()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 31
ccs 0
cts 24
cp 0
rs 8.439
cc 5
eloc 18
nc 7
nop 3
crap 30
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\services;
10
11
use craft\elements\db\UserQuery;
12
use craft\helpers\ArrayHelper;
13
use flipbox\ember\exceptions\RecordNotFoundException;
14
use flipbox\ember\helpers\SiteHelper;
15
use flipbox\ember\services\traits\elements\MultiSiteAccessor;
16
use flipbox\organizations\db\OrganizationQuery;
17
use flipbox\organizations\elements\Organization as OrganizationElement;
18
use flipbox\organizations\Organizations as OrganizationPlugin;
19
use craft\elements\User as UserElement;
20
use flipbox\organizations\records\UserAssociation;
21
use yii\base\Component;
22
23
/**
24
 * @author Flipbox Factory <[email protected]>
25
 * @since 1.0.0
26
 *
27
 * @method OrganizationElement create($config = [])
28
 * @method OrganizationElement find($identifier, int $siteId = null)
29
 * @method OrganizationElement get($identifier, int $siteId = null)
30
 * @method OrganizationQuery getQuery($criteria = [])
31
 */
32
class Organizations extends Component
33
{
34
    use MultiSiteAccessor;
35
36
    /**
37
     * @inheritdoc
38
     */
39
    public static function elementClass(): string
40
    {
41
        return OrganizationElement::class;
42
    }
43
44
    /**
45
     * @param $identifier
46
     * @param int|null $siteId
47
     * @return array
48
     */
49
    protected function identifierCondition($identifier, int $siteId = null): array
50
    {
51
        $base = [
52
            'siteId' => SiteHelper::ensureSiteId($siteId),
53
            'status' => null
54
        ];
55
56
        if (is_array($identifier)) {
57
            return array_merge($base, $identifier);
58
        }
59
60
        if (!is_numeric($identifier) && is_string($identifier)) {
61
            $base['slug'] = $identifier;
62
        } else {
63
            $base['id'] = $identifier;
64
        }
65
66
        return $base;
67
    }
68
69
    /**
70
     * @param mixed $organization
71
     * @return OrganizationElement
72
     */
73
    public function resolve($organization)
74
    {
75
        if (is_array($organization) &&
76
            null !== ($id = ArrayHelper::getValue($organization, 'id'))
77
        ) {
78
            return $this->get($id);
79
        }
80
81
        if ($object = $this->find($organization)) {
82
            return $object;
83
        }
84
85
        return $this->create($organization);
86
    }
87
88
    /**
89
     * @param UserQuery $query
90
     * @param OrganizationElement $organization
91
     * @return bool
92
     * @throws \Exception
93
     */
94
    public function saveAssociations(
95
        UserQuery $query,
96
        OrganizationElement $organization
97
    ): bool {
98
        /** @var UserElement[] $models */
99
        if (null === ($models = $query->getCachedResult())) {
100
            return true;
101
        }
102
103
        $models = $query->all();
104
105
        $associationService = OrganizationPlugin::getInstance()->getOrganizationUserAssociations();
106
107
        $query = $associationService->getQuery([
108
            $associationService::SOURCE_ATTRIBUTE => $organization->getId() ?: false
109
        ]);
110
111
        $query->setCachedResult(
112
            $this->toAssociations($models, $organization->getId())
113
        );
114
115
        return $associationService->save($query);
116
    }
117
118
    /**
119
     * @param UserQuery $query
120
     * @param OrganizationElement $organization
121
     * @return bool
122
     * @throws \Exception
123
     */
124
    public function dissociate(
125
        UserQuery $query,
126
        OrganizationElement $organization
127
    ): bool {
128
        return $this->associations(
129
            $query,
130
            $organization,
131
            [
132
                OrganizationPlugin::getInstance()->getOrganizationUserAssociations(),
133
                'dissociate'
134
            ]
135
        );
136
    }
137
138
    /**
139
     * @param UserQuery $query
140
     * @param OrganizationElement $organization
141
     * @return bool
142
     * @throws \Exception
143
     */
144
    public function associate(
145
        UserQuery $query,
146
        OrganizationElement $organization
147
    ): bool {
148
        return $this->associations(
149
            $query,
150
            $organization,
151
            [
152
                OrganizationPlugin::getInstance()->getOrganizationUserAssociations(),
153
                'associate'
154
            ]
155
        );
156
    }
157
158
    /**
159
     * @param UserQuery $query
160
     * @param OrganizationElement $organization
161
     * @param callable $callable
162
     * @return bool
163
     */
164
    protected function associations(UserQuery $query, OrganizationElement $organization, callable $callable)
165
    {
166
        /** @var UserElement[] $models */
167
        if (null === ($models = $query->getCachedResult())) {
168
            return true;
169
        }
170
171
        $models = ArrayHelper::index($models, 'id');
172
173
        $success = true;
174
        $ids = [];
175
        $count = count($models);
176
        $i = 0;
177
        foreach ($this->toAssociations($models, $organization->getId()) as $association) {
178
            if (true === call_user_func_array($callable, [$association, ++$i === $count])) {
179
                ArrayHelper::remove($models, $association->userId);
180
                $ids[] = $association->userId;
181
                continue;
182
            }
183
184
            $success = false;
185
        }
186
187
        $query->id($ids);
188
189
        if ($success === false) {
190
            $query->setCachedResult($models);
191
        }
192
193
        return $success;
194
    }
195
196
    /**
197
     * @param UserElement[] $users
198
     * @param int $organizationId
199
     * @return UserAssociation[]
200
     */
201
    private function toAssociations(
202
        array $users,
203
        int $organizationId
204
    ) {
205
        $associations = [];
206
        $sortOrder = 1;
207
208
        $associationService = OrganizationPlugin::getInstance()->getOrganizationUserAssociations();
209
        $sortOrderAttribute = $associationService::SORT_ORDER_ATTRIBUTE;
210
211
        $existingAssociations = $associationService->findAllByCriteria([
212
            'where' => [
213
                $associationService::TARGET_ATTRIBUTE => ArrayHelper::getColumn($users, 'id'),
214
                $associationService::SOURCE_ATTRIBUTE => $organizationId,
215
            ],
216
            'indexBy' => $associationService::TARGET_ATTRIBUTE
217
        ]);
218
219
        foreach ($users as $user) {
220
            if (null === ($association = ArrayHelper::remove($existingAssociations, $user->getId()))) {
221
                $association = $associationService->create([
222
                    'userId' => (int) $user->getId(),
223
                    'organizationId' => (int) $organizationId
224
                ]);
225
            }
226
227
            $association->{$sortOrderAttribute} = $sortOrder++;
228
            $associations[] = $association;
229
        }
230
231
        return $associations;
232
    }
233
234
    /*******************************************
235
     * EXCEPTIONS
236
     *******************************************/
237
238
    /**
239
     * @throws RecordNotFoundException
240
     */
241
    protected function recordNotFoundException()
242
    {
243
        throw new RecordNotFoundException('Record does not exist.');
244
    }
245
}
246