Organization::setMember()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 2
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\organization\elements\db;
10
11
use Craft;
12
use craft\db\Query;
13
use craft\elements\db\ElementQuery;
14
use craft\elements\User as UserElement;
15
use craft\helpers\ArrayHelper;
16
use craft\helpers\Db;
17
use craft\models\UserGroup;
18
use craft\records\UserGroup as UserGroupRecord;
19
use craft\records\UserGroup_User as UserGroupUsersRecord;
20
use flipbox\organization\elements\Organization as OrganizationElement;
21
use flipbox\organization\helpers\Query as QueryHelper;
22
use flipbox\organization\models\Type;
23
use flipbox\organization\Organization as OrganizationPlugin;
24
use flipbox\organization\records\Organization as OrganizationRecord;
25
use flipbox\organization\records\OrganizationType as OrganizationTypeOrganizationRecord;
26
use flipbox\organization\records\User as OrganizationUserRecord;
27
28
/**
29
 * @author Flipbox Factory <[email protected]>
30
 * @since 1.0.0
31
 *
32
 * @method OrganizationElement|null one($db = null)
33
 * @method OrganizationElement[] all($db = null)
34
 */
35
class Organization extends ElementQuery
36
{
37
38
    /**
39
     * @var int|int[]|null The user ID(s) that the resulting organizations’ owners must have.
40
     */
41
    public $ownerId;
42
43
    /**
44
     * @var int|int[]|null The user group ID(s) that the resulting organizations’ owners must be in.
45
     */
46
    public $ownerGroupId;
47
48
    /**
49
     * @var int|int[]|null The organization type ID(s) that the resulting organizations must have.
50
     */
51
    public $typeId;
52
53
    /**
54
     * @var int|int[]|null The organization type ID(s) that the resulting organizations must have.
55
     */
56
    public $userId;
57
58
    /**
59
     * @var int|int[]|null The organization type ID(s) that the resulting organizations must have.
60
     */
61
    public $memberId;
62
63
    /**
64
     * @var mixed The Join Date that the resulting organization must have.
65
     */
66
    public $dateJoined;
67
68
    /**
69
     * @inheritdoc
70
     */
71
    public function __set($name, $value)
72
    {
73
74
        switch ($name) {
75
            case 'owner':
76
            case 'ownerId':
77
                $this->setOwner($value);
78
                break;
79
            case 'ownerGroup':
80
                $this->ownerGroup($value);
81
                break;
82
            case 'type':
83
            case 'typeId':
84
                $this->setType($value);
85
                break;
86
            case 'user':
87
            case 'userId':
88
                $this->setUser($value);
89
                break;
90
            case 'member':
91
            case 'memberId':
92
                $this->setMember($value);
93
                break;
94
            default:
95
                parent::__set($name, $value);
96
        }
97
    }
98
99
100
    /**
101
     * Sets the [[typeId]] property based on a given element owner.
102
     *
103
     * @param string|string[]|integer|integer[]|Type|Type[] $value The property value
104
     *
105
     * @return self The query object itself
106
     */
107
    public function setType($value)
108
    {
109
110
        $this->typeId = $this->parseTypeValue($value);
111
112
        return $this;
113
    }
114
115
    /**
116
     * Sets the [[typeId]] property.
117
     *
118
     * @param string|string[]|integer|integer[]|Type|Type[] $type The property value
119
     *
120
     * @return self The query object itself
121
     */
122
    public function type($type)
123
    {
124
125
        $this->setType($type);
126
127
        return $this;
128
    }
129
130
    /**
131
     * @param $typeId
132
     * @return $this
133
     */
134
    public function setTypeId($typeId)
135
    {
136
137
        $this->setType($typeId);
138
139
        return $this;
140
    }
141
142
    /**
143
     * Sets the [[typeId]] property.
144
     *
145
     * @param integer|integer[] $type The property value
146
     *
147
     * @return self The query object itself
148
     */
149
    public function typeId($type)
150
    {
151
152
        $this->setType($type);
153
154
        return $this;
155
    }
156
157
    /**
158
     * Sets the [[ownerId]] property based on a given element owner.
159
     *
160
     * @param string|string[]|integer|integer[]|UserElement|UserElement[] $value The property value
161
     *
162
     * @return self The query object itself
163
     */
164
    public function setOwner($value)
165
    {
166
167
        // parse param to allow for mixed variables
168
        $this->ownerId = $this->parseUserValue($value);
169
170
        return $this;
171
    }
172
173
    /**
174
     * Sets the [[ownerId]] property.
175
     *
176
     * @param string|string[]|integer|integer[]|UserElement|UserElement[] $owner The property value
177
     *
178
     * @return self The query object itself
179
     */
180
    public function owner($owner)
181
    {
182
183
        $this->setOwner($owner);
184
185
        return $this;
186
    }
187
188
    /**
189
     * @param $ownerId
190
     * @return $this
191
     */
192
    public function setOwnerId($ownerId)
193
    {
194
195
        $this->setOwner($ownerId);
196
197
        return $this;
198
    }
199
200
    /**
201
     * Sets the [[ownerId]] property.
202
     *
203
     * @param integer|integer[] $owner The property value
204
     *
205
     * @return self The query object itself
206
     */
207
    public function ownerId($owner)
208
    {
209
210
        $this->setOwner($owner);
211
212
        return $this;
213
    }
214
215
216
    /**
217
     * Sets the [[ownerGroupId]] property based on a given user group(s)’s handle(s).
218
     *
219
     * @param string|string[]|null $value The property value
220
     *
221
     * @return static self reference
222
     */
223
    public function ownerGroup($value)
224
    {
225
        if ($value instanceof UserGroup) {
226
            $this->ownerGroupId = $value->id;
227
        } elseif ($value !== null) {
228
            $this->ownerGroupId = (new Query())
229
                ->select(['id'])
230
                ->from([UserGroupRecord::tableName()])
231
                ->where(Db::parseParam('handle', $value))
232
                ->column();
233
        } else {
234
            $this->ownerGroupId = null;
235
        }
236
237
        return $this;
238
    }
239
240
    /**
241
     * Sets the [[authorGroupId]] property.
242
     *
243
     * @param int|int[]|null $value The property value
244
     *
245
     * @return static self reference
246
     */
247
    public function ownerGroupId($value)
248
    {
249
        $this->ownerGroupId = $value;
250
251
        return $this;
252
    }
253
254
255
    /**
256
     * Sets the [[userId]] property based on a given element owner.
257
     *
258
     * @param string|string[]|integer|integer[]|UserElement|UserElement[] $value The property value
259
     *
260
     * @return self The query object itself
261
     */
262
    public function setUser($value)
263
    {
264
265
        $this->userId = $this->parseUserValue($value);
266
267
        return $this;
268
    }
269
270
    /**
271
     * Sets the [[userId]] property.
272
     *
273
     * @param string|string[]|integer|integer[]|UserElement|UserElement[] $users The property value
274
     *
275
     * @return self The query object itself
276
     */
277
    public function user($users)
278
    {
279
280
        $this->setUser($users);
281
282
        return $this;
283
    }
284
285
    /**
286
     * @param $userIds
287
     * @return $this
288
     */
289
    public function setUserId($userIds)
290
    {
291
292
        $this->setUser($userIds);
293
294
        return $this;
295
    }
296
297
    /**
298
     * Sets the [[userId]] property.
299
     *
300
     * @param integer|integer[] $user The property value
301
     *
302
     * @return self The query object itself
303
     */
304
    public function userId($user)
305
    {
306
307
        $this->setUser($user);
308
309
        return $this;
310
    }
311
312
    /**
313
     * Sets the [[userId]] property based on a given element owner.
314
     *
315
     * @param string|string[]|integer|integer[]|UserElement|UserElement[] $value The property value
316
     *
317
     * @return self The query object itself
318
     */
319
    public function setMember($value)
320
    {
321
322
        $this->memberId = $this->parseUserValue($value);
323
324
        return $this;
325
    }
326
327
    /**
328
     * Sets the [[userId]] property.
329
     *
330
     * @param string|string[]|integer|integer[]|UserElement|UserElement[] $members The property value
331
     *
332
     * @return self The query object itself
333
     */
334
    public function member($members)
335
    {
336
337
        $this->setMember($members);
338
339
        return $this;
340
    }
341
342
    /**
343
     * @param $memberIds
344
     * @return $this
345
     */
346
    public function setMemberId($memberIds)
347
    {
348
349
        $this->setMember($memberIds);
350
351
        return $this;
352
    }
353
354
    /**
355
     * Sets the [[userId]] property.
356
     *
357
     * @param integer|integer[] $member The property value
358
     *
359
     * @return self The query object itself
360
     */
361
    public function memberId($member)
362
    {
363
364
        $this->setMember($member);
365
366
        return $this;
367
    }
368
369
    /**
370
     * Sets the [[dateJoined]] property.
371
     *
372
     * @param mixed $value The property value
373
     *
374
     * @return static self reference
375
     */
376
    public function dateJoined($value)
377
    {
378
        $this->dateJoined = $value;
379
380
        return $this;
381
    }
382
383
    /**
384
     * @inheritdoc
385
     */
386
    protected function statusCondition(string $status)
387
    {
388
389
        $statuses = OrganizationPlugin::getInstance()->getSettings()->getStatuses();
390
391
        if (array_key_exists($status, $statuses)) {
392
            return [OrganizationRecord::tableAlias() . '.status' => $status];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(\flipbox\or... '.status' => $status); (array<string,string>) is incompatible with the return type of the parent method craft\elements\db\ElementQuery::statusCondition of type array<string,string>|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
393
        }
394
395
        return parent::statusCondition($status);
396
    }
397
398
    /**
399
     * @inheritdoc
400
     */
401
    protected function beforePrepare(): bool
402
    {
403
404
        // invalid handles
405
        if ($this->ownerGroupId === []) {
406
            return false;
407
        }
408
409
        $alias = OrganizationRecord::tableAlias();
410
411
        $this->joinElementTable($alias);
412
413
        $this->query->select([
414
            $alias . '.status',
415
            $alias . '.ownerId',
416
            $alias . '.dateJoined'
417
        ]);
418
419
        if ($this->dateJoined) {
420
            $this->subQuery->andWhere(Db::parseDateParam($alias . '.dateJoined', $this->dateJoined));
421
        }
422
423
        if ($this->typeId) {
424
            $this->subQuery->innerJoin(
425
                $this->organizationDbTableReference(),
426
                'elements.id = ' . OrganizationTypeOrganizationRecord::tableAlias() . '.organizationId'
427
            );
428
429
            $this->subQuery->andWhere(Db::parseParam(
430
                OrganizationTypeOrganizationRecord::tableAlias() . '.typeId',
431
                $this->typeId
432
            ));
433
        }
434
435
        // Owner only
436
        if ($this->ownerId) {
437
            $this->subQuery->andWhere(Db::parseParam($alias . '.ownerId', $this->ownerId));
438
        }
439
440
        if ($this->ownerGroupId) {
441
            $this->subQuery
442
                ->innerJoin(
443
                    UserGroupUsersRecord::tableName() . ' usergroups_users',
444
                    '[[usergroups_users.userId]] = [[' . $alias . '.ownerId]]'
445
                )
446
                ->andWhere(Db::parseParam('usergroups_users.groupId', $this->ownerGroupId));
447
        }
448
449
        // Join user table
450
        if ($this->userId || $this->memberId) {
451
            $this->subQuery->leftJoin(
452
                OrganizationUserRecord::tableName() . ' ' . OrganizationUserRecord::tableAlias(),
453
                'elements.id = ' . OrganizationUserRecord::tableAlias() . '.organizationId'
454
            );
455
            $this->subQuery->addSelect([OrganizationUserRecord::tableAlias() . '.sortOrder']);
456
        }
457
458
        // User only
459
        if ($this->userId) {
460
            $this->subQuery->andWhere(
461
                Db::parseParam(OrganizationUserRecord::tableAlias() . '.userId', $this->userId)
462
            );
463
        }
464
465
        // User or Owner
466
        if ($this->memberId) {
467
            $this->subQuery->distinct(true);
468
            $this->subQuery->andWhere([
469
                'or',
470
                Db::parseParam(OrganizationUserRecord::tableAlias() . '.userId', $this->memberId),
471
                Db::parseParam($alias . '.ownerId', $this->memberId)
472
            ]);
473
        }
474
475
        return parent::beforePrepare();
476
    }
477
478
    /**
479
     * @return string
480
     */
481
    private function organizationDbTableReference(): string
482
    {
483
        return OrganizationTypeOrganizationRecord::tableName() . ' ' . OrganizationTypeOrganizationRecord::tableAlias();
484
    }
485
486
    /**
487
     * @param $value
488
     * @return array
489
     */
490
    private function parseTypeValue($value)
491
    {
492
493
        // Default join type
494
        $join = 'or';
495
496
        // Parse as single param?
497
        if (false === QueryHelper::parseBaseParam($value, $join)) {
498
            // Add one by one
499
            foreach ($value as $operator => &$v) {
500
                // attempt to assemble value (return false if it's a handle)
501
                if (false === QueryHelper::findParamValue($v, $operator)) {
502
                    // create new query
503
                    if (is_string($v)) {
504
                        if ($model = OrganizationPlugin::getInstance()->getType()->find($v)) {
505
                            $v = $model;
506
                        }
507
                    }
508
509
                    if ($v instanceof Type) {
510
                        $v = $v->id;
511
                    }
512
513
                    if ($v) {
514
                        $v = QueryHelper::assembleParamValue($v, $operator);
515
                    }
516
                }
517
            }
518
        }
519
520
        // parse param to allow for mixed variables
521
        return array_merge([$join], ArrayHelper::filterEmptyStringsFromArray($value));
522
    }
523
524
    /**
525
     * @param $value
526
     * @return array
527
     */
528
    private function parseUserValue($value)
529
    {
530
531
        // Default join type
532
        $join = 'and';
533
534
        // Parse as single param?
535
        if (false === QueryHelper::parseBaseParam($value, $join)) {
536
            // Add one by one
537
            foreach ($value as $operator => &$v) {
538
                // attempt to assemble value (return false if it's a handle)
539
                if (false === QueryHelper::findParamValue($v, $operator)) {
540
                    // get element by string
541
                    if (is_string($v)) {
542
                        if ($element = Craft::$app->getUsers()->getUserByUsernameOrEmail($v)) {
543
                            $v = $element->id;
544
                        }
545
                    }
546
547
                    if ($v instanceof UserElement) {
548
                        $v = $v->id;
549
                    }
550
551
                    if ($v) {
552
                        $v = QueryHelper::assembleParamValue($v, $operator);
553
                    }
554
                }
555
            }
556
        }
557
558
        // parse param to allow for mixed variables
559
        return array_merge([$join], ArrayHelper::filterEmptyStringsFromArray($value));
560
    }
561
}
562