This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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\organization\elements; |
||
10 | |||
11 | use Craft; |
||
12 | use craft\base\Element; |
||
13 | use craft\db\Query; |
||
14 | use craft\elements\actions\Edit as EditAction; |
||
15 | use craft\elements\db\ElementQueryInterface; |
||
16 | use craft\elements\db\UserQuery; |
||
17 | use craft\elements\User; |
||
0 ignored issues
–
show
|
|||
18 | use craft\helpers\ArrayHelper; |
||
19 | use craft\helpers\StringHelper; |
||
20 | use craft\helpers\UrlHelper as UrlHelper; |
||
21 | use craft\validators\DateTimeValidator; |
||
22 | use DateTime; |
||
23 | use flipbox\organization\elements\actions\ChangeOrganizationStatus as StatusAction; |
||
24 | use flipbox\organization\elements\actions\DeleteOrganization as DeleteAction; |
||
25 | use flipbox\organization\elements\db\Organization as OrganizationQuery; |
||
26 | use flipbox\organization\helpers\Type as TypeHelper; |
||
27 | use flipbox\organization\helpers\User as UserHelper; |
||
28 | use flipbox\organization\models\Type as TypeModel; |
||
29 | use flipbox\organization\Organization as OrganizationPlugin; |
||
30 | use flipbox\organization\records\Organization as OrganizationRecord; |
||
31 | use flipbox\organization\records\User as OrganizationUsersRecord; |
||
32 | use flipbox\organization\validators\Owner; |
||
33 | use flipbox\spark\helpers\ElementHelper; |
||
34 | use flipbox\spark\helpers\QueryHelper; |
||
35 | use yii\base\ErrorException as Exception; |
||
36 | |||
37 | /** |
||
38 | * @author Flipbox Factory <[email protected]> |
||
39 | * @since 1.0.0 |
||
40 | */ |
||
41 | class Organization extends Element |
||
42 | { |
||
43 | |||
44 | /** |
||
45 | * @var string |
||
46 | */ |
||
47 | private $status; |
||
48 | |||
49 | /** |
||
50 | * @var DateTime|null |
||
51 | */ |
||
52 | public $dateJoined; |
||
53 | |||
54 | /** |
||
55 | * @var int |
||
56 | */ |
||
57 | public $ownerId; |
||
58 | |||
59 | /** |
||
60 | * @var User |
||
61 | */ |
||
62 | private $owner; |
||
63 | |||
64 | /** |
||
65 | * @var TypeModel[] |
||
66 | */ |
||
67 | private $types; |
||
68 | |||
69 | /** |
||
70 | * @var TypeModel |
||
71 | */ |
||
72 | private $activeType; |
||
73 | |||
74 | /** |
||
75 | * @var TypeModel |
||
76 | */ |
||
77 | private $primaryType; |
||
78 | |||
79 | /** |
||
80 | * @var UserQuery |
||
81 | */ |
||
82 | private $users; |
||
83 | |||
84 | /** |
||
85 | * @var UserQuery |
||
86 | */ |
||
87 | private $members; |
||
88 | |||
89 | /** |
||
90 | * @inheritdoc |
||
91 | */ |
||
92 | public static function displayName(): string |
||
93 | { |
||
94 | return Craft::t('organization', 'Organization'); |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * @inheritdoc |
||
99 | */ |
||
100 | public static function hasTitles(): bool |
||
101 | { |
||
102 | return true; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * @inheritdoc |
||
107 | */ |
||
108 | public static function hasContent(): bool |
||
109 | { |
||
110 | return true; |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * @return array |
||
115 | */ |
||
116 | public function attributes() |
||
117 | { |
||
118 | return array_merge( |
||
119 | parent::attributes(), |
||
120 | [ |
||
121 | 'types', |
||
122 | 'activeType', |
||
123 | 'primaryType', |
||
124 | 'users', |
||
125 | ] |
||
126 | ); |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * @inheritdoc |
||
131 | */ |
||
132 | public function rules() |
||
133 | { |
||
134 | |||
135 | return array_merge( |
||
136 | parent::rules(), |
||
137 | [ |
||
138 | [ |
||
139 | [ |
||
140 | 'ownerId' |
||
141 | ], |
||
142 | 'number', |
||
143 | 'integerOnly' => true |
||
144 | |||
145 | ], |
||
146 | [ |
||
147 | [ |
||
148 | 'ownerId' |
||
149 | ], |
||
150 | Owner::class |
||
151 | ], |
||
152 | [ |
||
153 | [ |
||
154 | 'dateJoined' |
||
155 | ], |
||
156 | DateTimeValidator::class |
||
157 | ], |
||
158 | [ |
||
159 | [ |
||
160 | 'activeType', |
||
161 | 'primaryType', |
||
162 | 'ownerId', |
||
163 | 'owner', |
||
164 | 'types', |
||
165 | 'users', |
||
166 | 'members', |
||
167 | 'status' |
||
168 | ], |
||
169 | 'safe', |
||
170 | 'on' => [ |
||
171 | ElementHelper::SCENARIO_DEFAULT |
||
172 | ] |
||
173 | |||
174 | ], |
||
175 | ] |
||
176 | ); |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Returns the names of any attributes that should be converted to DateTime objects from [[populate()]]. |
||
181 | * |
||
182 | * @return string[] |
||
183 | */ |
||
184 | public function datetimeAttributes(): array |
||
185 | { |
||
186 | |||
187 | return array_merge( |
||
188 | parent::datetimeAttributes(), |
||
189 | [ |
||
190 | 'dateJoined' |
||
191 | ] |
||
192 | ); |
||
193 | } |
||
194 | |||
195 | |||
196 | /************************************************************ |
||
197 | * FIELD LAYOUT |
||
198 | ************************************************************/ |
||
199 | |||
200 | /** |
||
201 | * @inheritdoc |
||
202 | */ |
||
203 | public function getFieldLayout(int $siteId = null) |
||
204 | { |
||
205 | |||
206 | /** @var TypeModel $type */ |
||
207 | if (!$type = $this->getActiveType()) { |
||
208 | return OrganizationPlugin::getInstance()->getOrganization()->getDefaultFieldLayout(); |
||
209 | } |
||
210 | |||
211 | return $type->getFieldLayout($siteId); |
||
212 | } |
||
213 | |||
214 | |||
215 | /************************************************************ |
||
216 | * FIND / GET |
||
217 | ************************************************************/ |
||
218 | |||
219 | /** |
||
220 | * @inheritdoc |
||
221 | * |
||
222 | * @return OrganizationQuery |
||
223 | */ |
||
224 | public static function find(): ElementQueryInterface |
||
225 | { |
||
226 | return new OrganizationQuery(get_called_class()); |
||
227 | } |
||
228 | |||
229 | |||
230 | /************************************************************ |
||
231 | * STATUS |
||
232 | ************************************************************/ |
||
233 | |||
234 | /** |
||
235 | * Returns whether this element type can have statuses. |
||
236 | * |
||
237 | * @return boolean |
||
238 | */ |
||
239 | public static function hasStatuses(): bool |
||
240 | { |
||
241 | return true; |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * @inheritdoc |
||
246 | */ |
||
247 | public static function statuses(): array |
||
248 | { |
||
249 | return OrganizationPlugin::getInstance()->getOrganization()->getStatuses(); |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * @param $status |
||
254 | * @return $this |
||
255 | */ |
||
256 | public function setStatus($status) |
||
257 | { |
||
258 | |||
259 | $this->status = null; |
||
260 | |||
261 | // A custom organization status |
||
262 | if (OrganizationPlugin::getInstance()->getOrganization()->isCustomStatus($status)) { |
||
263 | $this->archived = 0; |
||
0 ignored issues
–
show
The property
$archived was declared of type boolean , but 0 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
264 | $this->enabled = 1; |
||
0 ignored issues
–
show
The property
$enabled was declared of type boolean , but 1 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
265 | $this->enabledForSite = 1; |
||
0 ignored issues
–
show
The property
$enabledForSite was declared of type boolean , but 1 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
266 | |||
267 | $this->status = $status; |
||
268 | } else { |
||
269 | switch ($status) { |
||
270 | case Element::STATUS_ENABLED: |
||
271 | $this->enabled = 1; |
||
272 | $this->enabledForSite = 1; |
||
273 | break; |
||
274 | |||
275 | case Element::STATUS_DISABLED: |
||
276 | $this->enabled = 0; |
||
0 ignored issues
–
show
The property
$enabled was declared of type boolean , but 0 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
277 | break; |
||
278 | |||
279 | case Element::STATUS_ARCHIVED: |
||
280 | $this->archived = 1; |
||
0 ignored issues
–
show
The property
$archived was declared of type boolean , but 1 is of type integer . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
281 | break; |
||
282 | } |
||
283 | } |
||
284 | |||
285 | return $this; |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * @inheritdoc |
||
290 | */ |
||
291 | public function getStatus() |
||
292 | { |
||
293 | |||
294 | if (null === $this->status) { |
||
295 | return parent::getStatus(); |
||
296 | } |
||
297 | |||
298 | return $this->status; |
||
299 | } |
||
300 | |||
301 | /************************************************************ |
||
302 | * ACTIVE TYPE |
||
303 | ************************************************************/ |
||
304 | |||
305 | /** |
||
306 | * @param TypeModel|null $type |
||
307 | * @return $this |
||
308 | */ |
||
309 | public function setActiveType(TypeModel $type = null) |
||
310 | { |
||
311 | |||
312 | if ($type) { |
||
313 | $this->addType($type); |
||
314 | } |
||
315 | |||
316 | $this->activeType = (null === $type) ? false : $type; |
||
317 | return $this; |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * @return TypeModel|null |
||
322 | */ |
||
323 | public function getActiveType() |
||
324 | { |
||
325 | |||
326 | if (null === $this->activeType) { |
||
327 | // Default to the primary type |
||
328 | if (!$activeType = $this->getPrimaryType()) { |
||
329 | // Set false vs null to indicate population has taken place |
||
330 | $activeType = false; |
||
331 | } |
||
332 | |||
333 | $this->activeType = $activeType; |
||
0 ignored issues
–
show
It seems like
$activeType can also be of type false . However, the property $activeType is declared as type object<flipbox\organization\models\Type> . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
334 | } |
||
335 | |||
336 | return (false === $this->activeType) ? null : $this->activeType; |
||
337 | } |
||
338 | |||
339 | |||
340 | /************************************************************ |
||
341 | * PRIMARY TYPE |
||
342 | ************************************************************/ |
||
343 | |||
344 | /** |
||
345 | * Populate the primary type |
||
346 | */ |
||
347 | protected function ensurePrimaryType() |
||
348 | { |
||
349 | |||
350 | if (null === $this->primaryType) { |
||
351 | if (!$primaryType = OrganizationPlugin::getInstance()->getType()->findPrimaryByOrganization($this)) { |
||
352 | // Set false vs null to indicate population has taken place |
||
353 | $primaryType = false; |
||
354 | } |
||
355 | |||
356 | // Set cache |
||
357 | $this->primaryType = $primaryType; |
||
358 | } |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Identify whether a primary type is set |
||
363 | * |
||
364 | * @return bool |
||
365 | */ |
||
366 | public function hasPrimaryType() |
||
367 | { |
||
368 | |||
369 | $this->ensurePrimaryType(); |
||
370 | |||
371 | return $this->primaryType instanceof TypeModel; |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * Identify whether the type is primary |
||
376 | * |
||
377 | * @param $type |
||
378 | * @return bool |
||
379 | */ |
||
380 | public function isPrimaryType(TypeModel $type) |
||
381 | { |
||
382 | |||
383 | if ($primaryType = $this->getPrimaryType()) { |
||
384 | return $primaryType->id === $type->id; |
||
385 | } |
||
386 | |||
387 | return false; |
||
388 | } |
||
389 | |||
390 | /** |
||
391 | * @param TypeModel $type |
||
392 | * @return $this |
||
393 | */ |
||
394 | public function setPrimaryType(TypeModel $type) |
||
395 | { |
||
396 | |||
397 | $this->primaryType = $type; |
||
398 | |||
399 | // Remove active type cache |
||
400 | if (false === $this->activeType) { |
||
401 | $this->activeType = null; |
||
402 | } |
||
403 | |||
404 | return $this; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * Get the primary type |
||
409 | * |
||
410 | * @return TypeModel|null |
||
411 | */ |
||
412 | public function getPrimaryType() |
||
413 | { |
||
414 | |||
415 | if (!$this->hasPrimaryType()) { |
||
416 | return null; |
||
417 | } |
||
418 | |||
419 | return $this->primaryType; |
||
420 | } |
||
421 | |||
422 | /************************************************************ |
||
423 | * TYPES |
||
424 | ************************************************************/ |
||
425 | |||
426 | /** |
||
427 | * Associate a type to the element |
||
428 | * |
||
429 | * @param TypeModel $type |
||
430 | * @return $this |
||
431 | */ |
||
432 | public function addType(TypeModel $type) |
||
433 | { |
||
434 | |||
435 | $this->ensureTypes(); |
||
436 | |||
437 | // Already set? |
||
438 | if (!array_key_exists($type->id, $this->types)) { |
||
439 | $this->types[$type->id] = $type; |
||
440 | } |
||
441 | |||
442 | return $this; |
||
443 | } |
||
444 | |||
445 | /** |
||
446 | * Set the types associated to the element |
||
447 | * |
||
448 | * @param null $types |
||
449 | * @return $this |
||
450 | */ |
||
451 | public function setTypes($types = null) |
||
452 | { |
||
453 | |||
454 | $this->types = []; |
||
455 | |||
456 | // In case a type config is directly passed |
||
457 | if (!is_array($types) || ArrayHelper::isAssociative($types)) { |
||
458 | $types = [$types]; |
||
459 | } |
||
460 | |||
461 | foreach ($types as $type) { |
||
462 | if ($type = TypeHelper::resolve($type)) { |
||
463 | $this->addType($type); |
||
464 | } |
||
465 | } |
||
466 | |||
467 | return $this; |
||
468 | } |
||
469 | |||
470 | /** |
||
471 | * Get all associated types associated to the element |
||
472 | * |
||
473 | * @return TypeModel[] |
||
474 | */ |
||
475 | public function getTypes(): array |
||
476 | { |
||
477 | |||
478 | $this->ensureTypes(); |
||
479 | |||
480 | return $this->types; |
||
481 | } |
||
482 | |||
483 | /** |
||
484 | * Ensure all types are associated to the element |
||
485 | * |
||
486 | * @return $this |
||
487 | */ |
||
488 | private function ensureTypes() |
||
489 | { |
||
490 | |||
491 | if (null === $this->types) { |
||
492 | $this->types = ArrayHelper::index( |
||
493 | OrganizationPlugin::getInstance()->getType()->findAllByOrganization($this), |
||
494 | 'id' |
||
495 | ); |
||
496 | } |
||
497 | |||
498 | return $this; |
||
499 | } |
||
500 | |||
501 | /** |
||
502 | * Get an associated type by identifier (id/handle) |
||
503 | * |
||
504 | * @param $identifier |
||
505 | * @return null|TypeModel |
||
506 | */ |
||
507 | public function getType($identifier) |
||
508 | { |
||
509 | |||
510 | // Determine index type |
||
511 | $indexBy = (is_numeric($identifier)) ? 'id' : 'handle'; |
||
512 | |||
513 | // Find all types |
||
514 | $allTypes = ArrayHelper::index( |
||
515 | $this->getTypes(), |
||
516 | $indexBy |
||
517 | ); |
||
518 | |||
519 | return array_key_exists($identifier, $allTypes) ? $allTypes[$identifier] : null; |
||
520 | } |
||
521 | |||
522 | /** |
||
523 | * Identify whether a type is associated to the element |
||
524 | * |
||
525 | * @param TypeModel|null $type |
||
526 | * @return bool |
||
527 | */ |
||
528 | public function hasType(TypeModel $type = null): bool |
||
529 | { |
||
530 | |||
531 | // Check if any type is set |
||
532 | if (null === $type) { |
||
533 | return !empty($this->getTypes()); |
||
534 | } |
||
535 | |||
536 | return null !== $this->getType($type->id); |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * @param TypeModel|null $type |
||
541 | * @return bool |
||
542 | * @deprecated |
||
543 | */ |
||
544 | public function getHasType(TypeModel $type = null): bool |
||
545 | { |
||
546 | |||
547 | Craft::$app->getDeprecator()->log( |
||
548 | __METHOD__, |
||
549 | 'Use "hasType()" method' |
||
550 | ); |
||
551 | |||
552 | return $this->hasType($type); |
||
553 | } |
||
554 | |||
555 | |||
556 | /************************************************************ |
||
557 | * MEMBERS |
||
558 | ************************************************************/ |
||
559 | /** |
||
560 | * Get an array of users associated to an organization |
||
561 | * |
||
562 | * @param array $criteria |
||
563 | * @return UserQuery |
||
564 | */ |
||
565 | public function getMembers($criteria = []) |
||
566 | { |
||
567 | |||
568 | if (null === $this->members) { |
||
569 | $this->members = OrganizationPlugin::getInstance()->getOrganization()->getMemberQuery($this); |
||
570 | } |
||
571 | |||
572 | if (!empty($criteria)) { |
||
573 | QueryHelper::configure( |
||
574 | $this->members, |
||
575 | $criteria |
||
576 | ); |
||
577 | } |
||
578 | |||
579 | return $this->members; |
||
580 | } |
||
581 | |||
582 | /** |
||
583 | * Associate users to an organization |
||
584 | * |
||
585 | * @param $members |
||
586 | * @return $this |
||
587 | */ |
||
588 | protected function setMembers($members) |
||
589 | { |
||
590 | |||
591 | // Reset the query |
||
592 | $this->members = OrganizationPlugin::getInstance()->getOrganization()->getMemberQuery($this); |
||
593 | |||
594 | // Remove all users |
||
595 | $this->members->setCachedResult([]); |
||
596 | |||
597 | $this->addMembers($members); |
||
598 | |||
599 | return $this; |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * Associate an array of users to an organization |
||
604 | * |
||
605 | * @param $members |
||
606 | * @return $this |
||
607 | */ |
||
608 | protected function addMembers(array $members) |
||
609 | { |
||
610 | |||
611 | // In case a type config is directly passed |
||
612 | if (!is_array($members) || ArrayHelper::isAssociative($members)) { |
||
613 | $members = [$members]; |
||
614 | } |
||
615 | |||
616 | foreach ($members as $key => $user) { |
||
617 | // Ensure we have a model |
||
618 | if (!$user instanceof User) { |
||
619 | $user = UserHelper::resolve($user); |
||
620 | } |
||
621 | |||
622 | $this->addMember($user); |
||
0 ignored issues
–
show
It seems like
$user can be null ; however, addMember() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
623 | } |
||
624 | |||
625 | return $this; |
||
626 | } |
||
627 | |||
628 | /** |
||
629 | * Associate a user to an organization |
||
630 | * |
||
631 | * @param User $user |
||
632 | * @param bool $addAsUser |
||
633 | * @return $this |
||
634 | */ |
||
635 | protected function addMember(User $user, bool $addAsUser = true) |
||
636 | { |
||
637 | |||
638 | $currentUsers = $this->getMembers()->all(); |
||
639 | |||
640 | $userElementsByEmail = ArrayHelper::index( |
||
641 | $currentUsers, |
||
642 | 'email' |
||
643 | ); |
||
644 | |||
645 | // Does the user already exist? |
||
646 | if (!array_key_exists($user->email, $userElementsByEmail)) { |
||
647 | $currentUsers[] = $user; |
||
648 | $this->getMembers()->setCachedResult($currentUsers); |
||
649 | } |
||
650 | |||
651 | // Add as a 'user' as well? |
||
652 | if ($addAsUser) { |
||
653 | $this->addUser($user, false); |
||
654 | } |
||
655 | |||
656 | return $this; |
||
657 | } |
||
658 | |||
659 | |||
660 | /************************************************************ |
||
661 | * USERS |
||
662 | ************************************************************/ |
||
663 | |||
664 | /** |
||
665 | * Get an array of users associated to an organization |
||
666 | * |
||
667 | * @param array $criteria |
||
668 | * @return UserQuery |
||
669 | */ |
||
670 | public function getUsers($criteria = []) |
||
671 | { |
||
672 | |||
673 | if (null === $this->users) { |
||
674 | $this->users = OrganizationPlugin::getInstance()->getOrganization()->getUserQuery($this); |
||
675 | } |
||
676 | |||
677 | if (!empty($criteria)) { |
||
678 | QueryHelper::configure( |
||
679 | $this->users, |
||
680 | $criteria |
||
681 | ); |
||
682 | } |
||
683 | |||
684 | return $this->users; |
||
685 | } |
||
686 | |||
687 | /** |
||
688 | * @param User $user |
||
689 | * @param array $criteria |
||
690 | * @return bool |
||
691 | */ |
||
692 | public function isUser(User $user, $criteria = []) |
||
693 | { |
||
694 | |||
695 | Craft::$app->getDeprecator()->log( |
||
696 | __METHOD__, |
||
697 | 'Moved into service. Organization::isUser()' |
||
698 | ); |
||
699 | |||
700 | return OrganizationPlugin::getInstance()->getOrganization()->isUser($user, $this, $criteria); |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * Associate users to an organization |
||
705 | * |
||
706 | * @param $users |
||
707 | * @return $this |
||
708 | */ |
||
709 | public function setUsers($users) |
||
710 | { |
||
711 | |||
712 | // Reset the query |
||
713 | $this->users = OrganizationPlugin::getInstance()->getOrganization()->getUserQuery($this); |
||
714 | |||
715 | // Remove all users |
||
716 | $this->users->setCachedResult([]); |
||
717 | |||
718 | $this->addUsers($users); |
||
719 | |||
720 | return $this; |
||
721 | } |
||
722 | |||
723 | /** |
||
724 | * Associate an array of users to an organization |
||
725 | * |
||
726 | * @param $users |
||
727 | * @return $this |
||
728 | */ |
||
729 | public function addUsers(array $users) |
||
730 | { |
||
731 | |||
732 | // In case a type config is directly passed |
||
733 | if (!is_array($users) || ArrayHelper::isAssociative($users)) { |
||
734 | $users = [$users]; |
||
735 | } |
||
736 | |||
737 | foreach ($users as $key => $user) { |
||
738 | // Ensure we have a model |
||
739 | if (!$user instanceof User) { |
||
740 | $user = UserHelper::resolve($user); |
||
741 | } |
||
742 | |||
743 | $this->addUser($user); |
||
0 ignored issues
–
show
It seems like
$user can be null ; however, addUser() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
744 | } |
||
745 | |||
746 | return $this; |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * Associate a user to an organization |
||
751 | * |
||
752 | * @param User $user |
||
753 | * @param bool $addAsMember |
||
754 | * @return $this |
||
755 | */ |
||
756 | public function addUser(User $user, bool $addAsMember = true) |
||
757 | { |
||
758 | |||
759 | $currentUsers = $this->getUsers()->all(); |
||
760 | |||
761 | $userElementsByEmail = ArrayHelper::index( |
||
762 | $currentUsers, |
||
763 | 'email' |
||
764 | ); |
||
765 | |||
766 | // Does the user already exist? |
||
767 | if (!array_key_exists($user->email, $userElementsByEmail)) { |
||
768 | $currentUsers[] = $user; |
||
769 | $this->getUsers()->setCachedResult($currentUsers); |
||
770 | } |
||
771 | |||
772 | if ($addAsMember) { |
||
773 | $this->addMember($user, false); |
||
774 | } |
||
775 | |||
776 | return $this; |
||
777 | } |
||
778 | |||
779 | /** |
||
780 | * Dissociate a user from an organization |
||
781 | * |
||
782 | * @param array $users |
||
783 | * @return $this |
||
784 | */ |
||
785 | public function removeUsers(array $users) |
||
786 | { |
||
787 | |||
788 | // In case a type config is directly passed |
||
789 | if (!is_array($users) || ArrayHelper::isAssociative($users)) { |
||
790 | $users = [$users]; |
||
791 | } |
||
792 | |||
793 | foreach ($users as $key => $user) { |
||
794 | // Ensure we have a model |
||
795 | if (!$user instanceof User) { |
||
796 | $user = UserHelper::resolve($user); |
||
797 | } |
||
798 | |||
799 | $this->removeUser($user); |
||
0 ignored issues
–
show
It seems like
$user can be null ; however, removeUser() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
800 | } |
||
801 | |||
802 | return $this; |
||
803 | } |
||
804 | |||
805 | /** |
||
806 | * Dissociate a user from an organization |
||
807 | * |
||
808 | * @param User $user |
||
809 | * @return $this |
||
810 | */ |
||
811 | public function removeUser(User $user) |
||
812 | { |
||
813 | |||
814 | $userElementsByEmail = ArrayHelper::index( |
||
815 | $this->getUsers()->all(), |
||
816 | 'email' |
||
817 | ); |
||
818 | |||
819 | // Does the user already exist? |
||
820 | if (array_key_exists($user->email, $userElementsByEmail)) { |
||
821 | unset($userElementsByEmail[$user->email]); |
||
822 | |||
823 | $this->getUsers()->setCachedResult( |
||
824 | array_values($userElementsByEmail) |
||
825 | ); |
||
826 | } |
||
827 | |||
828 | return $this; |
||
829 | } |
||
830 | |||
831 | /** |
||
832 | * Associate an array of types from request input |
||
833 | * |
||
834 | * @param string $identifier |
||
835 | * @return $this |
||
836 | */ |
||
837 | public function setTypesFromRequest(string $identifier = 'types') |
||
838 | { |
||
839 | |||
840 | // Set users array |
||
841 | $this->setTypes( |
||
842 | Craft::$app->getRequest()->getBodyParam($identifier, []) |
||
843 | ); |
||
844 | |||
845 | return $this; |
||
846 | } |
||
847 | |||
848 | /** |
||
849 | * Associate an array of users from request input |
||
850 | * |
||
851 | * @param string $identifier |
||
852 | * @return $this |
||
853 | */ |
||
854 | public function setUsersFromRequest(string $identifier = 'users') |
||
855 | { |
||
856 | |||
857 | if ($users = Craft::$app->getRequest()->getBodyParam($identifier, [])) { |
||
858 | // Set users array |
||
859 | $this->setUsers($users); |
||
860 | } |
||
861 | |||
862 | return $this; |
||
863 | } |
||
864 | |||
865 | |||
866 | /************************************************************ |
||
867 | * ELEMENT ADMIN |
||
868 | ************************************************************/ |
||
869 | |||
870 | /** |
||
871 | * @inheritdoc |
||
872 | */ |
||
873 | public function getCpEditUrl() |
||
874 | { |
||
875 | return UrlHelper::cpUrl('organization/' . $this->id); |
||
876 | } |
||
877 | |||
878 | /** |
||
879 | * @inheritdoc |
||
880 | */ |
||
881 | protected static function defineSources(string $context = null): array |
||
882 | { |
||
883 | |||
884 | switch ($context) { |
||
885 | case 'user': |
||
886 | return self::defineUserSources(); |
||
887 | |||
888 | case 'owner': |
||
889 | return self::defineOwnerSources(); |
||
890 | |||
891 | default: |
||
892 | return self::defineTypeSources(); |
||
893 | } |
||
894 | } |
||
895 | |||
896 | /** |
||
897 | * @return array |
||
898 | */ |
||
899 | private static function defineDefaultSources(): array |
||
900 | { |
||
901 | |||
902 | return [ |
||
903 | [ |
||
904 | 'key' => '*', |
||
905 | 'label' => Craft::t('app', 'All organizations'), |
||
906 | 'criteria' => ['status' => null], |
||
907 | 'hasThumbs' => true |
||
908 | ] |
||
909 | ]; |
||
910 | } |
||
911 | |||
912 | /** |
||
913 | * @return array |
||
914 | */ |
||
915 | private static function defineTypeSources(): array |
||
916 | { |
||
917 | |||
918 | $sources = static::defineDefaultSources(); |
||
0 ignored issues
–
show
Since
defineDefaultSources() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self , or increase the visibility of defineDefaultSources() to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return static::getTemperature();
}
} The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass {
private static function getTemperature() {
return "-182 °C";
}
}
print YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return self::getTemperature();
}
}
![]() |
|||
919 | |||
920 | // Array of all organization types |
||
921 | $organizationTypes = OrganizationPlugin::getInstance()->getType()->findAll(); |
||
922 | |||
923 | $sources[] = ['heading' => Craft::t('organization', 'Types')]; |
||
924 | |||
925 | /** @var TypeModel $organizationType */ |
||
926 | foreach ($organizationTypes as $organizationType) { |
||
927 | $sources[] = [ |
||
928 | 'key' => 'type:' . $organizationType->id, |
||
929 | 'label' => $organizationType->name, |
||
930 | 'criteria' => ['status' => null, 'typeId' => $organizationType->id], |
||
931 | 'hasThumbs' => true |
||
932 | ]; |
||
933 | } |
||
934 | |||
935 | return $sources; |
||
936 | } |
||
937 | |||
938 | /** |
||
939 | * @return array |
||
940 | */ |
||
941 | private static function defineUserSources(): array |
||
942 | { |
||
943 | |||
944 | $sources = static::defineDefaultSources(); |
||
0 ignored issues
–
show
Since
defineDefaultSources() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self , or increase the visibility of defineDefaultSources() to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return static::getTemperature();
}
} The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass {
private static function getTemperature() {
return "-182 °C";
}
}
print YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return self::getTemperature();
}
}
![]() |
|||
945 | |||
946 | // Array of all organization types |
||
947 | $organizationUsers = OrganizationPlugin::getInstance()->getUser()->getQuery(); |
||
948 | |||
949 | $sources[] = ['heading' => Craft::t('organization', 'Users')]; |
||
950 | |||
951 | /** @var User $organizationUser */ |
||
952 | foreach ($organizationUsers as $organizationUser) { |
||
953 | $sources[] = [ |
||
954 | 'key' => 'user:' . $organizationUser->id, |
||
955 | 'label' => $organizationUser->getFullName(), |
||
956 | 'criteria' => [ |
||
957 | 'status' => null, |
||
958 | 'users' => [$organizationUser->id] |
||
959 | ], |
||
960 | 'hasThumbs' => true |
||
961 | ]; |
||
962 | } |
||
963 | |||
964 | return $sources; |
||
965 | } |
||
966 | |||
967 | /** |
||
968 | * @return array |
||
969 | */ |
||
970 | private static function defineOwnerSources(): array |
||
971 | { |
||
972 | |||
973 | $sources = static::defineDefaultSources(); |
||
0 ignored issues
–
show
Since
defineDefaultSources() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self , or increase the visibility of defineDefaultSources() to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return static::getTemperature();
}
} The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass {
private static function getTemperature() {
return "-182 °C";
}
}
print YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return self::getTemperature();
}
}
![]() |
|||
974 | |||
975 | // Array of all organization types |
||
976 | $organizationOwners = OrganizationPlugin::getInstance()->getUser()->getOwnerQuery(); |
||
977 | |||
978 | $sources[] = ['heading' => Craft::t('organization', 'Users')]; |
||
979 | |||
980 | /** @var User $organizationOwner */ |
||
981 | foreach ($organizationOwners as $organizationOwner) { |
||
982 | $sources[] = [ |
||
983 | 'key' => 'owner:' . $organizationOwner->id, |
||
984 | 'label' => $organizationOwner->getFullName(), |
||
985 | 'criteria' => [ |
||
986 | 'status' => null, |
||
987 | 'ownerId' => $organizationOwner->id |
||
988 | ], |
||
989 | 'hasThumbs' => true |
||
990 | ]; |
||
991 | } |
||
992 | |||
993 | return $sources; |
||
994 | } |
||
995 | |||
996 | /** |
||
997 | * @inheritdoc |
||
998 | */ |
||
999 | protected static function defineActions(string $source = null): array |
||
1000 | { |
||
1001 | |||
1002 | $actions = []; |
||
1003 | |||
1004 | // Edit |
||
1005 | $actions[] = Craft::$app->getElements()->createAction([ |
||
1006 | 'type' => EditAction::class, |
||
1007 | 'label' => Craft::t('app', 'Edit organization'), |
||
1008 | ]); |
||
1009 | |||
1010 | if (Craft::$app->getUser()->checkPermission('administrateOrganizations')) { |
||
1011 | // Change status |
||
1012 | $actions[] = StatusAction::class; |
||
1013 | } |
||
1014 | |||
1015 | if (Craft::$app->getUser()->checkPermission('deleteOrganizations')) { |
||
1016 | // Delete |
||
1017 | $actions[] = DeleteAction::class; |
||
1018 | } |
||
1019 | |||
1020 | return $actions; |
||
1021 | } |
||
1022 | |||
1023 | /** |
||
1024 | * @inheritdoc |
||
1025 | */ |
||
1026 | protected static function defineSearchableAttributes(): array |
||
1027 | { |
||
1028 | return [ |
||
1029 | 'id', |
||
1030 | 'status' |
||
1031 | ]; |
||
1032 | } |
||
1033 | |||
1034 | /** |
||
1035 | * @inheritdoc |
||
1036 | */ |
||
1037 | protected static function defineSortOptions(): array |
||
1038 | { |
||
1039 | |||
1040 | return [ |
||
1041 | 'title' => Craft::t('organization', 'Name'), |
||
1042 | 'ownerId' => Craft::t('organization', 'Owner'), |
||
1043 | 'dateJoined' => Craft::t('organization', 'Join Date'), |
||
1044 | 'status' => Craft::t('organization', 'Status'), |
||
1045 | 'type' => Craft::t('organization', 'Type') |
||
1046 | ]; |
||
1047 | } |
||
1048 | |||
1049 | /** |
||
1050 | * @inheritdoc |
||
1051 | */ |
||
1052 | public static function eagerLoadingMap(array $sourceElements, string $handle) |
||
1053 | { |
||
1054 | |||
1055 | switch ($handle) { |
||
1056 | case 'owner': |
||
1057 | return self::eagerLoadingOwnerMap($sourceElements); |
||
1058 | |||
1059 | case 'users': |
||
1060 | return self::eagerLoadingUsersMap($sourceElements); |
||
1061 | |||
1062 | case 'members': |
||
1063 | return ArrayHelper::merge( |
||
1064 | self::eagerLoadingUsersMap($sourceElements), |
||
1065 | self::eagerLoadingOwnerMap($sourceElements) |
||
1066 | ); |
||
1067 | } |
||
1068 | |||
1069 | return parent::eagerLoadingMap($sourceElements, $handle); |
||
1070 | } |
||
1071 | |||
1072 | /** |
||
1073 | * @param array $sourceElements |
||
1074 | * @return array |
||
1075 | */ |
||
1076 | private static function eagerLoadingOwnerMap(array $sourceElements) |
||
1077 | { |
||
1078 | |||
1079 | // Get the source element IDs |
||
1080 | $sourceElementIds = ArrayHelper::getColumn($sourceElements, 'id'); |
||
1081 | |||
1082 | $map = (new Query()) |
||
1083 | ->select(['id as source', 'ownerId as target']) |
||
1084 | ->from(OrganizationRecord::tableName()) |
||
1085 | ->where(['id' => $sourceElementIds]) |
||
1086 | ->all(); |
||
1087 | |||
1088 | return [ |
||
1089 | 'elementType' => User::class, |
||
1090 | 'map' => $map |
||
1091 | ]; |
||
1092 | } |
||
1093 | |||
1094 | /** |
||
1095 | * @param array $sourceElements |
||
1096 | * @return array |
||
1097 | */ |
||
1098 | private static function eagerLoadingUsersMap(array $sourceElements) |
||
1099 | { |
||
1100 | |||
1101 | // Get the source element IDs |
||
1102 | $sourceElementIds = ArrayHelper::getColumn($sourceElements, 'id'); |
||
1103 | |||
1104 | $map = (new Query()) |
||
1105 | ->select(['organizationId as source', 'userId as target']) |
||
1106 | ->from(OrganizationUsersRecord::tableName()) |
||
1107 | ->where(['organizationId' => $sourceElementIds]) |
||
1108 | ->all(); |
||
1109 | |||
1110 | return [ |
||
1111 | 'elementType' => User::class, |
||
1112 | 'map' => $map |
||
1113 | ]; |
||
1114 | } |
||
1115 | |||
1116 | |||
1117 | /** |
||
1118 | * @inheritdoc |
||
1119 | */ |
||
1120 | public function setEagerLoadedElements(string $handle, array $elements) |
||
1121 | { |
||
1122 | |||
1123 | switch ($handle) { |
||
1124 | case 'owner': |
||
1125 | $owner = $elements[0] ?? null; |
||
1126 | $this->setOwner($owner); |
||
1127 | break; |
||
1128 | |||
1129 | case 'users': |
||
1130 | $users = $elements ?? []; |
||
1131 | $this->setUsers($users); |
||
1132 | break; |
||
1133 | |||
1134 | case 'members': |
||
1135 | $users = $elements ?? []; |
||
1136 | $this->setMembers($users); |
||
1137 | break; |
||
1138 | |||
1139 | default: |
||
1140 | parent::setEagerLoadedElements($handle, $elements); |
||
1141 | } |
||
1142 | } |
||
1143 | |||
1144 | /** |
||
1145 | * @inheritdoc |
||
1146 | */ |
||
1147 | public static function defineTableAttributes(): array |
||
1148 | { |
||
1149 | return [ |
||
1150 | 'id' => ['label' => Craft::t('app', 'ID')], |
||
1151 | 'uri' => ['label' => Craft::t('app', 'URI')], |
||
1152 | 'title' => ['label' => Craft::t('organization', 'Name')], |
||
1153 | 'owner' => ['label' => Craft::t('organization', 'Owner')], |
||
1154 | 'status' => ['label' => Craft::t('organization', 'Status')], |
||
1155 | 'types' => ['label' => Craft::t('organization', 'Type(s)')], |
||
1156 | 'dateJoined' => ['label' => Craft::t('organization', 'Join Date')], |
||
1157 | 'dateCreated' => ['label' => Craft::t('app', 'Date Created')], |
||
1158 | 'dateUpdated' => ['label' => Craft::t('app', 'Date Updated')], |
||
1159 | ]; |
||
1160 | } |
||
1161 | |||
1162 | |||
1163 | |||
1164 | // Indexes, etc. |
||
1165 | // ------------------------------------------------------------------------- |
||
1166 | |||
1167 | /** |
||
1168 | * @inheritdoc |
||
1169 | */ |
||
1170 | public function tableAttributeHtml(string $attribute): string |
||
1171 | { |
||
1172 | |||
1173 | switch ($attribute) { |
||
1174 | case 'status': |
||
1175 | $value = $this->getStatus(); |
||
1176 | $availableStatuses = self::statuses(); |
||
1177 | if (array_key_exists($value, $availableStatuses)) { |
||
1178 | return '<span class="status ' . $value . '"></span> ' . ucfirst($availableStatuses[$value]); |
||
1179 | } |
||
1180 | return $value . $availableStatuses; |
||
1181 | |||
1182 | case 'owner': |
||
1183 | if ($this->hasOwner()) { |
||
1184 | return '<span class="status ' . $this->getOwner()->getStatus() . '"></span>' . |
||
1185 | $this->getOwner()->getFullName(); |
||
1186 | } |
||
1187 | |||
1188 | return ''; |
||
1189 | |||
1190 | case 'types': |
||
1191 | // Get all configured types |
||
1192 | $types = $this->getTypes(); |
||
1193 | |||
1194 | foreach ($types as $type) { |
||
1195 | $typeHtmlParts[] = '<a href="' . |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$typeHtmlParts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $typeHtmlParts = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
1196 | UrlHelper::cpUrl('/organization/' . $this->id . '/' . $type->handle) . |
||
1197 | '">' . |
||
1198 | $type->name . |
||
1199 | '</a>'; |
||
1200 | } |
||
1201 | |||
1202 | return !empty($typeHtmlParts) ? StringHelper::toString($typeHtmlParts, ', ') : ''; |
||
1203 | } |
||
1204 | |||
1205 | return parent::tableAttributeHtml($attribute); |
||
1206 | } |
||
1207 | |||
1208 | |||
1209 | /** |
||
1210 | * @inheritdoc |
||
1211 | */ |
||
1212 | protected function route() |
||
1213 | { |
||
1214 | |||
1215 | // Make sure that the organization is actually live |
||
1216 | if (in_array($this->getStatus(), [Element::STATUS_DISABLED, Element::STATUS_ARCHIVED], true)) { |
||
1217 | return null; |
||
1218 | } |
||
1219 | |||
1220 | // todo - match on other organization types or than primary? |
||
1221 | |||
1222 | // Use primary type as the element route |
||
1223 | if (!$primaryType = $this->getPrimaryType()) { |
||
1224 | return null; |
||
1225 | } |
||
1226 | |||
1227 | $primaryTypeSettings = $primaryType->getSite(); |
||
1228 | |||
1229 | if (!$primaryTypeSettings->hasUrls) { |
||
1230 | return null; |
||
1231 | } |
||
1232 | |||
1233 | return [ |
||
1234 | 'templates/render', [ |
||
1235 | 'template' => $primaryTypeSettings->template, |
||
1236 | 'variables' => [ |
||
1237 | 'organization' => $this, |
||
1238 | ] |
||
1239 | ] |
||
1240 | ]; |
||
1241 | } |
||
1242 | |||
1243 | // Events |
||
1244 | // ------------------------------------------------------------------------- |
||
1245 | |||
1246 | /** |
||
1247 | * @inheritdoc |
||
1248 | * @throws Exception |
||
1249 | */ |
||
1250 | public function beforeSave(bool $isNew): bool |
||
1251 | { |
||
1252 | |||
1253 | OrganizationPlugin::getInstance()->getOrganization()->beforeSave($this, $isNew); |
||
1254 | |||
1255 | return parent::beforeSave($isNew); |
||
1256 | } |
||
1257 | |||
1258 | /** |
||
1259 | * @inheritdoc |
||
1260 | * @throws Exception |
||
1261 | */ |
||
1262 | public function afterSave(bool $isNew) |
||
1263 | { |
||
1264 | |||
1265 | OrganizationPlugin::getInstance()->getOrganization()->afterSave($this, $isNew); |
||
1266 | |||
1267 | parent::afterSave($isNew); |
||
1268 | } |
||
1269 | |||
1270 | /** |
||
1271 | * Identify whether element has an owner |
||
1272 | * |
||
1273 | * @return bool |
||
1274 | */ |
||
1275 | public function hasOwner() |
||
1276 | { |
||
1277 | // Get owner if it already isn't set |
||
1278 | if (is_null($this->owner)) { |
||
1279 | $this->getOwner(); |
||
1280 | } |
||
1281 | |||
1282 | return $this->owner instanceof User; |
||
1283 | } |
||
1284 | |||
1285 | /** |
||
1286 | * @return bool|User|null |
||
1287 | */ |
||
1288 | public function getOwner() |
||
1289 | { |
||
1290 | |||
1291 | // Check cache |
||
1292 | if (is_null($this->owner)) { |
||
1293 | // Check property |
||
1294 | if (!empty($this->ownerId)) { |
||
1295 | // Find element |
||
1296 | if ($ownerElement = Craft::$app->getUsers()->getUserById($this->ownerId)) { |
||
1297 | // Set |
||
1298 | $this->setOwner($ownerElement); |
||
1299 | } else { |
||
1300 | // Clear property (it's invalid) |
||
1301 | $this->ownerId = null; |
||
1302 | |||
1303 | // Prevent subsequent look-ups |
||
1304 | $this->owner = false; |
||
0 ignored issues
–
show
It seems like
false of type false is incompatible with the declared type object<craft\elements\User> of property $owner .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
1305 | } |
||
1306 | } else { |
||
1307 | // Prevent subsequent look-ups |
||
1308 | $this->owner = false; |
||
1309 | } |
||
1310 | } else { |
||
1311 | // Cache changed? |
||
1312 | if ($this->ownerId && (($this->owner === false) || ($this->ownerId !== $this->owner->getId()))) { |
||
1313 | // Clear cache |
||
1314 | $this->owner = null; |
||
1315 | |||
1316 | // Again |
||
1317 | return $this->getOwner(); |
||
1318 | } |
||
1319 | } |
||
1320 | |||
1321 | return $this->hasOwner() ? $this->owner : null; |
||
1322 | } |
||
1323 | |||
1324 | /** |
||
1325 | * Associate an owner to the element |
||
1326 | * |
||
1327 | * @param $owner |
||
1328 | * @return $this |
||
1329 | */ |
||
1330 | public function setOwner($owner) |
||
1331 | { |
||
1332 | |||
1333 | // Clear cache |
||
1334 | $this->owner = null; |
||
1335 | |||
1336 | // Find element |
||
1337 | if (!$owner = $this->findUserElement($owner)) { |
||
1338 | // Clear property / cache |
||
1339 | $this->ownerId = $this->owner = null; |
||
1340 | } else { |
||
1341 | // Set property |
||
1342 | $this->ownerId = $owner->getId(); |
||
1343 | |||
1344 | // Set cache |
||
1345 | $this->owner = $owner; |
||
1346 | } |
||
1347 | |||
1348 | return $this; |
||
1349 | } |
||
1350 | |||
1351 | /** |
||
1352 | * @param string $user |
||
1353 | * @return bool |
||
1354 | */ |
||
1355 | public function getIsOwner($user = 'CURRENT_USER') |
||
1356 | { |
||
1357 | |||
1358 | if ('CURRENT_USER' === $user) { |
||
1359 | // Current user |
||
1360 | $element = Craft::$app->getUser()->getIdentity(); |
||
1361 | } else { |
||
1362 | // Find element |
||
1363 | $element = $this->findUserElement($user); |
||
1364 | } |
||
1365 | |||
1366 | return ($element && $element->getId() == $this->ownerId); |
||
1367 | } |
||
1368 | |||
1369 | /** |
||
1370 | * @param string|User $user |
||
1371 | * @return bool |
||
1372 | */ |
||
1373 | public function isOwner($user = 'CURRENT_USER') |
||
1374 | { |
||
1375 | return $this->getIsOwner($user); |
||
0 ignored issues
–
show
It seems like
$user defined by parameter $user on line 1373 can also be of type object<craft\elements\User> ; however, flipbox\organization\ele...anization::getIsOwner() does only seem to accept string , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
1376 | } |
||
1377 | |||
1378 | /** |
||
1379 | * @param $user |
||
1380 | * @return User|null |
||
1381 | */ |
||
1382 | private function findUserElement($user) |
||
1383 | { |
||
1384 | |||
1385 | // Element |
||
1386 | if ($user instanceof User) { |
||
1387 | return $user; |
||
1388 | |||
1389 | // Id |
||
1390 | } elseif (is_numeric($user)) { |
||
1391 | return Craft::$app->getUsers()->getUserById($user); |
||
1392 | |||
1393 | // Username / Email |
||
1394 | } elseif (!is_null($user)) { |
||
1395 | return Craft::$app->getUsers()->getUserByUsernameOrEmail($user); |
||
1396 | } |
||
1397 | |||
1398 | return null; |
||
1399 | } |
||
1400 | } |
||
1401 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/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 beforeOtherDir/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: