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\organizations\elements; |
||
10 | |||
11 | use Craft; |
||
12 | use craft\base\Element; |
||
13 | use craft\elements\actions\Edit as EditAction; |
||
14 | use craft\elements\actions\SetStatus; |
||
15 | use craft\elements\db\ElementQueryInterface; |
||
16 | use craft\elements\User; |
||
17 | use craft\helpers\DateTimeHelper; |
||
18 | use craft\helpers\Json; |
||
19 | use craft\helpers\StringHelper; |
||
20 | use craft\helpers\UrlHelper as UrlHelper; |
||
21 | use flipbox\craft\ember\elements\ExplicitElementTrait; |
||
22 | use flipbox\craft\ember\helpers\ModelHelper; |
||
23 | use flipbox\organizations\models\DateJoinedAttributeTrait; |
||
24 | use flipbox\organizations\Organizations as OrganizationPlugin; |
||
25 | use flipbox\organizations\queries\OrganizationQuery; |
||
26 | use flipbox\organizations\records\Organization as OrganizationRecord; |
||
27 | use flipbox\organizations\records\OrganizationType; |
||
28 | use flipbox\organizations\records\OrganizationType as TypeModel; |
||
29 | use yii\base\ErrorException as Exception; |
||
30 | |||
31 | /** |
||
32 | * @author Flipbox Factory <[email protected]> |
||
33 | * @since 1.0.0 |
||
34 | * |
||
35 | * @method static Organization[] findAll($criteria = null) : array |
||
36 | */ |
||
37 | class Organization extends Element |
||
38 | { |
||
39 | use ExplicitElementTrait, |
||
40 | DateJoinedAttributeTrait, |
||
41 | TypesAttributeTrait, |
||
42 | UsersAttributeTrait; |
||
43 | |||
44 | /** |
||
45 | * Whether associated types should be saved |
||
46 | * |
||
47 | * @var bool |
||
48 | */ |
||
49 | private $saveTypes = true; |
||
50 | |||
51 | /** |
||
52 | * Whether associated users should be saved |
||
53 | * |
||
54 | * @var bool |
||
55 | */ |
||
56 | private $saveUsers = true; |
||
57 | |||
58 | /** |
||
59 | * @inheritdoc |
||
60 | */ |
||
61 | public static function displayName(): string |
||
62 | { |
||
63 | return Craft::t('organizations', 'Organization'); |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * @inheritdoc |
||
68 | */ |
||
69 | public function getIsEditable(): bool |
||
70 | { |
||
71 | return true; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * @inheritdoc |
||
76 | */ |
||
77 | public static function hasTitles(): bool |
||
78 | { |
||
79 | return true; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @inheritdoc |
||
84 | */ |
||
85 | public static function isLocalized(): bool |
||
86 | { |
||
87 | return true; |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * @inheritdoc |
||
92 | */ |
||
93 | public static function hasContent(): bool |
||
94 | { |
||
95 | return true; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * @inheritdoc |
||
100 | */ |
||
101 | public static function hasUris(): bool |
||
102 | { |
||
103 | return true; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Returns whether this element type can have statuses. |
||
108 | * |
||
109 | * @return boolean |
||
110 | */ |
||
111 | public static function hasStatuses(): bool |
||
112 | { |
||
113 | return true; |
||
114 | } |
||
115 | |||
116 | |||
117 | /************************************************************ |
||
118 | * QUERY |
||
119 | ************************************************************/ |
||
120 | |||
121 | /** |
||
122 | * @inheritdoc |
||
123 | * |
||
124 | * @return OrganizationQuery |
||
125 | */ |
||
126 | public static function find(): ElementQueryInterface |
||
127 | { |
||
128 | return new OrganizationQuery(static::class); |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * @inheritdoc |
||
133 | * @return static|null |
||
134 | */ |
||
135 | public static function findOne($criteria = null) |
||
136 | { |
||
137 | if ($criteria instanceof self) { |
||
138 | return $criteria; |
||
139 | } |
||
140 | |||
141 | // If we're asking by PK, ignore status |
||
142 | if (is_numeric($criteria)) { |
||
143 | $criteria = [ |
||
144 | 'id' => $criteria, |
||
145 | 'status' => null |
||
146 | ]; |
||
147 | } |
||
148 | |||
149 | return parent::findOne($criteria); |
||
0 ignored issues
–
show
Bug
Compatibility
introduced
by
Loading history...
|
|||
150 | } |
||
151 | |||
152 | /** |
||
153 | * @param mixed $criteria |
||
154 | * @param bool $one |
||
155 | * @return Element|Element[]|null |
||
156 | */ |
||
157 | protected static function findByCondition($criteria, bool $one) |
||
158 | { |
||
159 | if (is_numeric($criteria)) { |
||
160 | $criteria = ['id' => $criteria]; |
||
161 | } |
||
162 | |||
163 | if (is_string($criteria)) { |
||
164 | $criteria = ['slug' => $criteria]; |
||
165 | } |
||
166 | |||
167 | return parent::findByCondition($criteria, $one); |
||
168 | } |
||
169 | |||
170 | |||
171 | /************************************************************ |
||
172 | * PROPERTIES / ATTRIBUTES |
||
173 | ************************************************************/ |
||
174 | |||
175 | /** |
||
176 | * @return array |
||
177 | */ |
||
178 | public function attributes() |
||
179 | { |
||
180 | return array_merge( |
||
181 | parent::attributes(), |
||
182 | $this->dateJoinedAttributes() |
||
183 | ); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * @inheritdoc |
||
188 | * @throws \yii\base\InvalidConfigException |
||
189 | */ |
||
190 | public function rules() |
||
191 | { |
||
192 | return array_merge( |
||
193 | parent::rules(), |
||
194 | $this->dateJoinedRules(), |
||
195 | [ |
||
196 | [ |
||
197 | [ |
||
198 | 'types', |
||
199 | 'activeType', |
||
200 | 'primaryType', |
||
201 | 'users', |
||
202 | ], |
||
203 | 'safe', |
||
204 | 'on' => [ |
||
205 | ModelHelper::SCENARIO_DEFAULT |
||
0 ignored issues
–
show
The constant
flipbox\craft\ember\help...elper::SCENARIO_DEFAULT has been deprecated with message: Use `yii\base\Model::SCENARIO_DEFAULT`
This class constant has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.
Loading history...
|
|||
206 | ] |
||
207 | |||
208 | ], |
||
209 | ] |
||
210 | ); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * @return array |
||
215 | */ |
||
216 | public function attributeLabels() |
||
217 | { |
||
218 | return array_merge( |
||
219 | parent::attributeLabels(), |
||
220 | $this->dateJoinedAttributeLabels() |
||
221 | ); |
||
222 | } |
||
223 | |||
224 | |||
225 | /************************************************************ |
||
226 | * FIELD LAYOUT |
||
227 | ************************************************************/ |
||
228 | |||
229 | /** |
||
230 | * @inheritdoc |
||
231 | */ |
||
232 | public function getFieldLayout() |
||
233 | { |
||
234 | if (null === ($type = $this->getActiveType())) { |
||
235 | return OrganizationPlugin::getInstance()->getSettings()->getFieldLayout(); |
||
236 | } |
||
237 | |||
238 | return $type->getFieldLayout(); |
||
239 | } |
||
240 | |||
241 | |||
242 | /************************************************************ |
||
243 | * ELEMENT ADMIN |
||
244 | ************************************************************/ |
||
245 | |||
246 | /** |
||
247 | * @inheritdoc |
||
248 | */ |
||
249 | public function getRef() |
||
250 | { |
||
251 | if (!$primary = $this->getPrimaryType()) { |
||
252 | return $this->slug; |
||
253 | } |
||
254 | |||
255 | return $primary->handle . '/' . $this->slug; |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * @inheritdoc |
||
260 | */ |
||
261 | public function getCpEditUrl() |
||
262 | { |
||
263 | return UrlHelper::cpUrl('organizations/' . $this->id); |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * @inheritdoc |
||
268 | */ |
||
269 | protected static function defineSources(string $context = null): array |
||
270 | { |
||
271 | switch ($context) { |
||
272 | case 'user': |
||
273 | return self::defineUserSources(); |
||
274 | |||
275 | default: |
||
276 | return self::defineTypeSources(); |
||
277 | } |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * @return array |
||
282 | */ |
||
283 | private static function defineDefaultSources(): array |
||
284 | { |
||
285 | return [ |
||
286 | [ |
||
287 | 'key' => '*', |
||
288 | 'label' => Craft::t('organizations', 'All organizations'), |
||
289 | 'criteria' => ['status' => null], |
||
290 | 'hasThumbs' => true |
||
291 | ] |
||
292 | ]; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * @return array |
||
297 | */ |
||
298 | private static function defineTypeSources(): array |
||
299 | { |
||
300 | $sources = self::defineDefaultSources(); |
||
301 | |||
302 | // Array of all organization types |
||
303 | $organizationTypes = OrganizationType::findAll([]); |
||
304 | |||
305 | $sources[] = ['heading' => Craft::t('organizations', 'Types')]; |
||
306 | |||
307 | /** @var TypeModel $organizationType */ |
||
308 | foreach ($organizationTypes as $organizationType) { |
||
309 | $sources[] = [ |
||
310 | 'key' => 'type:' . $organizationType->id, |
||
311 | 'label' => $organizationType->name, |
||
312 | 'criteria' => ['status' => null, 'typeId' => $organizationType->id], |
||
313 | 'hasThumbs' => true |
||
314 | ]; |
||
315 | } |
||
316 | |||
317 | return $sources; |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * @return array |
||
322 | */ |
||
323 | private static function defineUserSources(): array |
||
324 | { |
||
325 | $sources = self::defineDefaultSources(); |
||
326 | |||
327 | // Array of all organization types |
||
328 | $organizationUsers = User::find(); |
||
329 | |||
330 | $sources[] = ['heading' => Craft::t('organizations', 'Users')]; |
||
331 | |||
332 | /** @var User $organizationUser */ |
||
333 | foreach ($organizationUsers as $organizationUser) { |
||
334 | $sources[] = [ |
||
335 | 'key' => 'user:' . $organizationUser->id, |
||
336 | 'label' => $organizationUser->getFullName(), |
||
337 | 'criteria' => [ |
||
338 | 'status' => null, |
||
339 | 'users' => [$organizationUser->id] |
||
340 | ], |
||
341 | 'hasThumbs' => true |
||
342 | ]; |
||
343 | } |
||
344 | |||
345 | return $sources; |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * @inheritdoc |
||
350 | */ |
||
351 | protected static function defineActions(string $source = null): array |
||
352 | { |
||
353 | $actions = []; |
||
354 | |||
355 | // Status |
||
356 | $actions[] = SetStatus::class; |
||
357 | |||
358 | // Edit |
||
359 | $actions[] = Craft::$app->getElements()->createAction([ |
||
360 | 'type' => EditAction::class, |
||
361 | 'label' => Craft::t('organizations', 'Edit'), |
||
362 | ]); |
||
363 | |||
364 | // if (Craft::$app->getUser()->checkPermission('deleteOrganizations')) { |
||
365 | // // Delete Organization |
||
366 | // $actions[] = DeleteAction::class; |
||
367 | // } |
||
368 | |||
369 | return $actions; |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * @inheritdoc |
||
374 | */ |
||
375 | protected static function defineSearchableAttributes(): array |
||
376 | { |
||
377 | return [ |
||
378 | 'id' |
||
379 | ]; |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * @inheritdoc |
||
384 | */ |
||
385 | protected static function defineSortOptions(): array |
||
386 | { |
||
387 | return [ |
||
388 | 'title' => Craft::t('organizations', 'Name'), |
||
389 | 'dateJoined' => Craft::t('organizations', 'Join Date'), |
||
390 | ]; |
||
391 | } |
||
392 | |||
393 | /** |
||
394 | * @inheritdoc |
||
395 | */ |
||
396 | public static function eagerLoadingMap(array $sourceElements, string $handle) |
||
397 | { |
||
398 | switch ($handle) { |
||
399 | case 'users': |
||
400 | return self::eagerLoadingUsersMap($sourceElements); |
||
401 | } |
||
402 | |||
403 | return parent::eagerLoadingMap($sourceElements, $handle); |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * @inheritdoc |
||
408 | */ |
||
409 | public function setEagerLoadedElements(string $handle, array $elements) |
||
410 | { |
||
411 | switch ($handle) { |
||
412 | case 'users': |
||
413 | $this->getUsers()->clear()->add($elements); |
||
414 | break; |
||
415 | |||
416 | default: |
||
417 | parent::setEagerLoadedElements($handle, $elements); |
||
418 | } |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * @inheritdoc |
||
423 | */ |
||
424 | public static function defineTableAttributes(): array |
||
425 | { |
||
426 | return [ |
||
427 | 'id' => ['label' => Craft::t('app', 'Name')], |
||
428 | 'uri' => ['label' => Craft::t('app', 'URI')], |
||
429 | 'types' => ['label' => Craft::t('organizations', 'Type(s)')], |
||
430 | 'dateJoined' => ['label' => Craft::t('organizations', 'Join Date')], |
||
431 | 'dateCreated' => ['label' => Craft::t('app', 'Date Created')], |
||
432 | 'dateUpdated' => ['label' => Craft::t('app', 'Date Updated')], |
||
433 | ]; |
||
434 | } |
||
435 | |||
436 | |||
437 | |||
438 | // Indexes, etc. |
||
439 | // ------------------------------------------------------------------------- |
||
440 | |||
441 | /** |
||
442 | * @inheritdoc |
||
443 | */ |
||
444 | public function tableAttributeHtml(string $attribute): string |
||
445 | { |
||
446 | |||
447 | switch ($attribute) { |
||
448 | case 'types': |
||
449 | $typeHtmlParts = []; |
||
450 | foreach ($this->getTypes()->getCollection() as $type) { |
||
451 | $typeHtmlParts[] = '<a href="' . |
||
452 | UrlHelper::cpUrl('organizations/' . $this->id . '/' . $type->handle) . |
||
453 | '">' . |
||
454 | $type->name . |
||
455 | '</a>'; |
||
456 | } |
||
457 | |||
458 | return !empty($typeHtmlParts) ? StringHelper::toString($typeHtmlParts, ', ') : ''; |
||
459 | } |
||
460 | |||
461 | return parent::tableAttributeHtml($attribute); |
||
462 | } |
||
463 | |||
464 | /** |
||
465 | * @inheritdoc |
||
466 | */ |
||
467 | public function getUriFormat() |
||
468 | { |
||
469 | if (null === ($siteSettings = $this->getSiteSettings())) { |
||
470 | return null; |
||
471 | } |
||
472 | |||
473 | if (!$siteSettings->hasUrls()) { |
||
474 | return null; |
||
475 | } |
||
476 | |||
477 | return $siteSettings->getUriFormat(); |
||
478 | } |
||
479 | |||
480 | /** |
||
481 | * @inheritdoc |
||
482 | */ |
||
483 | public function route() |
||
484 | { |
||
485 | if (in_array( |
||
486 | $this->getStatus(), |
||
487 | [static::STATUS_DISABLED, static::STATUS_ARCHIVED], |
||
488 | true |
||
489 | )) { |
||
490 | return null; |
||
491 | } |
||
492 | |||
493 | if (null === ($siteSettings = $this->getSiteSettings())) { |
||
494 | return null; |
||
495 | } |
||
496 | |||
497 | if (!$siteSettings->hasUrls()) { |
||
498 | return null; |
||
499 | } |
||
500 | |||
501 | return [ |
||
502 | 'templates/render', |
||
503 | [ |
||
504 | 'template' => $siteSettings->getTemplate(), |
||
505 | 'variables' => [ |
||
506 | 'organization' => $this, |
||
507 | ] |
||
508 | ] |
||
509 | ]; |
||
510 | } |
||
511 | |||
512 | /** |
||
513 | * @return \flipbox\organizations\records\OrganizationTypeSiteSettings|null |
||
514 | */ |
||
515 | protected function getSiteSettings() |
||
516 | { |
||
517 | try { |
||
518 | $settings = OrganizationPlugin::getInstance()->getSettings(); |
||
519 | $siteSettings = $settings->getSiteSettings()[$this->siteId] ?? null; |
||
520 | |||
521 | if (null !== ($type = $this->getPrimaryType())) { |
||
522 | $siteSettings = $type->getSiteSettings()[$this->siteId] ?? $siteSettings; |
||
523 | } |
||
524 | |||
525 | return $siteSettings; |
||
526 | } catch (\Exception $e) { |
||
527 | OrganizationPlugin::error( |
||
528 | sprintf( |
||
529 | "An exception was caught while to resolve site settings: %s", |
||
530 | $e->getMessage() |
||
531 | ) |
||
532 | ); |
||
533 | } |
||
534 | |||
535 | return null; |
||
536 | } |
||
537 | |||
538 | |||
539 | /************************************************************ |
||
540 | * EVENTS |
||
541 | ************************************************************/ |
||
542 | |||
543 | /** |
||
544 | * @inheritdoc |
||
545 | */ |
||
546 | public function save(bool $runValidation = true, bool $propagate = true): bool |
||
547 | { |
||
548 | return Craft::$app->getElements()->saveElement($this, $runValidation, $propagate); |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * @inheritdoc |
||
553 | */ |
||
554 | public function beforeSave(bool $isNew): bool |
||
555 | { |
||
556 | if (empty($this->getDateJoined())) { |
||
557 | $this->setDateJoined(DateTimeHelper::currentUTCDateTime()); |
||
558 | } |
||
559 | |||
560 | return parent::beforeSave($isNew); |
||
561 | } |
||
562 | |||
563 | /** |
||
564 | * @inheritdoc |
||
565 | * @throws /Exception |
||
566 | */ |
||
567 | public function afterSave(bool $isNew) |
||
568 | { |
||
569 | if (false === $this->saveRecord($isNew)) { |
||
570 | throw new Exception('Unable to save organization record'); |
||
571 | } |
||
572 | |||
573 | // Types |
||
574 | if (true === $this->saveTypes && false === $this->getTypes()->save()) { |
||
575 | throw new Exception("Unable to save types."); |
||
576 | } |
||
577 | |||
578 | // Users |
||
579 | if (true === $this->saveUsers && false === $this->getUsers()->save()) { |
||
580 | throw new Exception("Unable to save users."); |
||
581 | } |
||
582 | |||
583 | parent::afterSave($isNew); |
||
584 | } |
||
585 | |||
586 | |||
587 | /******************************************* |
||
588 | * RELATIONSHIP |
||
589 | *******************************************/ |
||
590 | |||
591 | /** |
||
592 | * @return static |
||
593 | */ |
||
594 | public function withTypes(): self |
||
595 | { |
||
596 | $this->saveTypes = true; |
||
597 | return $this; |
||
598 | } |
||
599 | |||
600 | /** |
||
601 | * @return static |
||
602 | */ |
||
603 | public function withoutTypes(): self |
||
604 | { |
||
605 | $this->saveTypes = false; |
||
606 | return $this; |
||
607 | } |
||
608 | |||
609 | /** |
||
610 | * @return static |
||
611 | */ |
||
612 | public function withUsers(): self |
||
613 | { |
||
614 | $this->saveUsers = true; |
||
615 | return $this; |
||
616 | } |
||
617 | |||
618 | /** |
||
619 | * @return static |
||
620 | */ |
||
621 | public function withoutUsers(): self |
||
622 | { |
||
623 | $this->saveUsers = false; |
||
624 | return $this; |
||
625 | } |
||
626 | |||
627 | /******************************************* |
||
628 | * RECORD |
||
629 | *******************************************/ |
||
630 | |||
631 | /** |
||
632 | * @param bool $isNew |
||
633 | * @return bool |
||
634 | * @throws \Exception |
||
635 | */ |
||
636 | protected function saveRecord(bool $isNew): bool |
||
637 | { |
||
638 | $record = $this->elementToRecord(); |
||
639 | |||
640 | if (!$record->save()) { |
||
641 | $this->addErrors($record->getErrors()); |
||
642 | |||
643 | OrganizationPlugin::error( |
||
644 | Json::encode($this->getErrors()), |
||
645 | __METHOD__ |
||
646 | ); |
||
647 | |||
648 | return false; |
||
649 | } |
||
650 | |||
651 | if (false !== ($dateUpdated = DateTimeHelper::toDateTime($record->dateUpdated))) { |
||
652 | $this->dateUpdated = $dateUpdated; |
||
653 | } |
||
654 | |||
655 | |||
656 | if ($isNew) { |
||
657 | $this->id = $record->id; |
||
658 | |||
659 | if (false !== ($dateCreated = DateTimeHelper::toDateTime($record->dateCreated))) { |
||
660 | $this->dateCreated = $dateCreated; |
||
661 | } |
||
662 | } |
||
663 | |||
664 | return true; |
||
665 | } |
||
666 | |||
667 | /** |
||
668 | * @inheritdoc |
||
669 | * @return OrganizationRecord |
||
670 | */ |
||
671 | protected function elementToRecord(): OrganizationRecord |
||
672 | { |
||
673 | if (!$record = OrganizationRecord::findOne([ |
||
674 | 'id' => $this->getId() |
||
675 | ])) { |
||
676 | $record = new OrganizationRecord(); |
||
677 | } |
||
678 | |||
679 | // PopulateOrganizationTypeTrait the record attributes |
||
680 | $record->id = $this->getId(); |
||
681 | $record->dateJoined = $this->getDateJoined(); |
||
682 | |||
683 | return $record; |
||
684 | } |
||
685 | } |
||
686 |