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 | * _ __ __ _____ _____ ___ ____ _____ |
||
5 | * | | / // // ___//_ _// || __||_ _| |
||
6 | * | |/ // /(__ ) / / / /| || | | | |
||
7 | * |___//_//____/ /_/ /_/ |_||_| |_| |
||
8 | * @link https://vistart.me/ |
||
9 | * @copyright Copyright (c) 2016 - 2017 vistart |
||
10 | * @license https://vistart.me/license/ |
||
11 | */ |
||
12 | |||
13 | namespace rhosocial\organization; |
||
14 | |||
15 | use rhosocial\base\models\queries\BaseBlameableQuery; |
||
16 | use rhosocial\organization\exceptions\RevokePreventedException; |
||
17 | use rhosocial\organization\queries\MemberQuery; |
||
18 | use rhosocial\organization\queries\OrganizationQuery; |
||
19 | use rhosocial\organization\rbac\permissions\SetUpOrganization; |
||
20 | use rhosocial\organization\rbac\permissions\SetUpDepartment; |
||
21 | use rhosocial\organization\rbac\permissions\RevokeOrganization; |
||
22 | use rhosocial\organization\rbac\permissions\RevokeDepartment; |
||
23 | use rhosocial\organization\rbac\roles\DepartmentAdmin; |
||
24 | use rhosocial\organization\rbac\roles\DepartmentCreator; |
||
25 | use rhosocial\organization\rbac\roles\OrganizationAdmin; |
||
26 | use rhosocial\organization\rbac\roles\OrganizationCreator; |
||
27 | use Yii; |
||
28 | use yii\base\Event; |
||
29 | use yii\base\InvalidConfigException; |
||
30 | use yii\base\InvalidParamException; |
||
31 | |||
32 | /** |
||
33 | * @property string $guidAttribute GUID Attribute. |
||
34 | * @property-read Member[] $ofMembers |
||
35 | * @property-read Member[] $ofCreators |
||
36 | * @property-read Member[] $ofAdministrators |
||
37 | * @property-read Organization[] $atOrganizations |
||
38 | * @property-read Organization[] $atOrganizationsOnly |
||
39 | * @property-read Organization[] $atDepartmentsOnly |
||
40 | * @property-read Organization[] $creatorsAtOrganizations |
||
41 | * @property-read Organization[] $creatorsAtOrganizationsOnly |
||
42 | * @property-read Organization[] $administratorsAtOrganizations |
||
43 | * @property-read Organization[] $administratorsAtOrganizationsOnly |
||
44 | * @property-read OrganizationLimit $organizationLimit |
||
45 | * |
||
46 | * @version 1.0 |
||
47 | * @author vistart <[email protected]> |
||
48 | */ |
||
49 | trait UserOrganizationTrait |
||
50 | { |
||
51 | /** |
||
52 | * @var string The organization class. |
||
53 | * Note: Please assign it with your own Organization class. |
||
54 | */ |
||
55 | public $organizationClass = Organization::class; |
||
56 | |||
57 | /** |
||
58 | * @var string The organization limit class. |
||
59 | * Note: Please assign it with your own OrganizationLimit class. |
||
60 | */ |
||
61 | public $organizationLimitClass = OrganizationLimit::class; |
||
62 | private $noInitOrganizationLimit; |
||
63 | private $noInitOrganization; |
||
64 | public $lastSetUpOrganization; |
||
65 | |||
66 | /** |
||
67 | * @return OrganizationLimit |
||
68 | */ |
||
69 | 51 | public function getNoInitOrganizationLimit() |
|
70 | { |
||
71 | 51 | if (!$this->noInitOrganizationLimit) { |
|
72 | 51 | $class = $this->organizationLimitClass; |
|
73 | 51 | $this->noInitOrganizationLimit = $class::buildNoInitModel(); |
|
74 | } |
||
75 | 51 | return $this->noInitOrganizationLimit; |
|
76 | } |
||
77 | /** |
||
78 | * @return Organization |
||
79 | */ |
||
80 | 51 | public function getNoInitOrganization() |
|
81 | { |
||
82 | 51 | if (!$this->noInitOrganization) { |
|
83 | 51 | $class = $this->organizationClass; |
|
84 | 51 | $this->noInitOrganization = $class::buildNoInitModel(); |
|
85 | } |
||
86 | 51 | return $this->noInitOrganization; |
|
87 | } |
||
88 | /** |
||
89 | * @return Member |
||
90 | */ |
||
91 | 51 | public function getNoInitMember() |
|
92 | { |
||
93 | 51 | return $this->getNoInitOrganization()->getNoInitMember(); |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * Get member query. |
||
98 | * @return MemberQuery |
||
99 | */ |
||
100 | 51 | public function getOfMembers() |
|
101 | { |
||
102 | 51 | return $this->hasMany(get_class($this->getNoInitMember()), [$this->getNoInitMember()->memberAttribute => $this->guidAttribute])->inverseOf('memberUser'); |
|
0 ignored issues
–
show
|
|||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Get query of member whose role is creator. |
||
107 | * @return MemberQuery |
||
108 | */ |
||
109 | 51 | public function getOfCreators() |
|
110 | { |
||
111 | 51 | return $this->getOfMembers()->andWhere(['role' => [(new DepartmentCreator)->name, (new OrganizationCreator)->name]]); |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * Get query of member whose role is administrator. |
||
116 | * @return MemberQuery |
||
117 | */ |
||
118 | 4 | public function getOfAdministrators() |
|
119 | { |
||
120 | 4 | return $this->getOfMembers()->andWhere(['role' => [(new DepartmentAdmin)->name, (new OrganizationAdmin)->name]]); |
|
121 | } |
||
122 | |||
123 | /** |
||
124 | * Get query of organization of which this user has been a member. |
||
125 | * If you access this method as magic-property `atOrganizations`, you will |
||
126 | * get all organizations the current user has joined in. |
||
127 | * @return OrganizationQuery |
||
128 | */ |
||
129 | 50 | public function getAtOrganizations() |
|
130 | { |
||
131 | 50 | return $this->hasMany($this->organizationClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->via('ofMembers'); |
|
0 ignored issues
–
show
It seems like
hasMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
132 | } |
||
133 | |||
134 | /** |
||
135 | * |
||
136 | * @return OrganizationQuery |
||
137 | */ |
||
138 | 2 | public function getAtOrganizationsOnly() |
|
139 | { |
||
140 | 2 | return $this->getAtOrganizations()->andWhere(['type' => Organization::TYPE_ORGANIZATION]); |
|
141 | } |
||
142 | |||
143 | /** |
||
144 | * |
||
145 | * @return OrganizationQuery |
||
146 | */ |
||
147 | 1 | public function getAtDepartmentsOnly() |
|
148 | { |
||
149 | 1 | return $this->getAtOrganizations()->andWhere(['type' => Organization::TYPE_DEPARTMENT]); |
|
150 | } |
||
151 | |||
152 | /** |
||
153 | * |
||
154 | * @return OrganizationQuery |
||
155 | */ |
||
156 | 51 | public function getCreatorsAtOrganizations() |
|
157 | { |
||
158 | 51 | return $this->hasMany($this->organizationClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->via('ofCreators'); |
|
0 ignored issues
–
show
It seems like
hasMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
159 | } |
||
160 | |||
161 | /** |
||
162 | * |
||
163 | * @return OrganizationQuery |
||
164 | */ |
||
165 | 51 | public function getCreatorsAtOrganizationsOnly() |
|
166 | { |
||
167 | 51 | return $this->getCreatorsAtOrganizations()->andWhere(['type' => Organization::TYPE_ORGANIZATION]); |
|
168 | } |
||
169 | |||
170 | /** |
||
171 | * |
||
172 | * @return OrganizationQuery |
||
173 | */ |
||
174 | 4 | public function getAdministratorsAtOrganizations() |
|
175 | { |
||
176 | 4 | return $this->hasMany($this->organizationClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->via('ofAdministrators'); |
|
0 ignored issues
–
show
It seems like
hasMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
177 | } |
||
178 | |||
179 | /** |
||
180 | * @return OrganizationQuery |
||
181 | */ |
||
182 | 2 | public function getAdministratorsAtOrganizationsOnly() |
|
183 | { |
||
184 | 2 | return $this->getAdministratorsAtOrganizations()->andWhere(['type' => Organization::TYPE_ORGANIZATION]); |
|
185 | } |
||
186 | |||
187 | /** |
||
188 | * Get Organization Limit Query. |
||
189 | * @return BaseBlameableQuery |
||
190 | */ |
||
191 | 51 | public function getOrganizationLimit() |
|
192 | { |
||
193 | 51 | if (empty($this->organizationLimitClass)) { |
|
194 | return null; |
||
195 | } |
||
196 | 51 | return $this->hasOne($this->organizationLimitClass, [$this->getNoInitOrganizationLimit()->createdByAttribute => $this->guidAttribute]); |
|
0 ignored issues
–
show
It seems like
hasOne() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Set up organization. |
||
201 | * @param string $name |
||
202 | * @param string $nickname |
||
203 | * @param integer $gravatar_type |
||
204 | * @param string $gravatar |
||
205 | * @param string $timezone |
||
206 | * @param string $description |
||
207 | * @return boolean Whether indicate the setting-up succeeded or not. |
||
208 | * @throws InvalidParamException |
||
209 | * @throws \Exception |
||
210 | */ |
||
211 | 51 | public function setUpOrganization($name, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '') |
|
212 | { |
||
213 | 51 | $accessChecker = Yii::$app->authManager; |
|
214 | 51 | if (!$accessChecker->checkAccess($this, (new SetUpOrganization)->name)) { |
|
215 | 1 | throw new InvalidParamException("You do not have permission to set up organization."); |
|
216 | } |
||
217 | 51 | $transaction = Yii::$app->db->beginTransaction(); |
|
218 | try { |
||
219 | 51 | $models = $this->createOrganization($name, null, $nickname, $gravatar_type, $gravatar, $timezone, $description); |
|
220 | 51 | $this->setUpBaseOrganization($models); |
|
221 | 50 | $transaction->commit(); |
|
222 | 1 | } catch (\Exception $ex) { |
|
223 | 1 | $transaction->rollBack(); |
|
224 | 1 | Yii::error($ex->getMessage(), __METHOD__); |
|
225 | 1 | throw $ex; |
|
226 | } |
||
227 | 50 | $this->lastSetUpOrganization = is_array($models) ? $models[0] : $models; |
|
228 | 50 | return true; |
|
229 | } |
||
230 | |||
231 | /** |
||
232 | * Set up organization. |
||
233 | * @param string $name Department name. |
||
234 | * @param Organization $parent Parent organization or department. |
||
235 | * @param string $nickname |
||
236 | * @param integer $gravatar_type |
||
237 | * @param string $gravatar |
||
238 | * @param string $timezone |
||
239 | * @param string $description |
||
240 | * @return boolean Whether indicate the setting-up succeeded or not. |
||
241 | * @throws InvalidParamException |
||
242 | * @throws \Exception |
||
243 | */ |
||
244 | 20 | public function setUpDepartment($name, $parent, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '') |
|
245 | { |
||
246 | 20 | if (!($parent instanceof $this->organizationClass)) { |
|
247 | 1 | throw new InvalidParamException('Invalid Parent Parameter.'); |
|
248 | } |
||
249 | 19 | $accessChecker = Yii::$app->authManager; |
|
250 | 19 | if (!$accessChecker->checkAccess($this, (new SetUpDepartment)->name, ['organization' => $parent])) { |
|
251 | 2 | throw new InvalidParamException("You do not have permission to set up department."); |
|
252 | } |
||
253 | 19 | $transaction = Yii::$app->db->beginTransaction(); |
|
254 | try { |
||
255 | 19 | $models = $this->createDepartment($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description); |
|
256 | 19 | $this->setUpBaseOrganization($models); |
|
257 | 18 | $transaction->commit(); |
|
258 | 1 | } catch (\Exception $ex) { |
|
259 | 1 | $transaction->rollBack(); |
|
260 | 1 | Yii::error($ex->getMessage(), __METHOD__); |
|
261 | 1 | throw $ex; |
|
262 | } |
||
263 | 18 | $this->lastSetUpOrganization = is_array($models) ? $models[0] : $models; |
|
264 | 18 | return true; |
|
265 | } |
||
266 | |||
267 | /** |
||
268 | * Set up base organization. |
||
269 | * @param Organization $models |
||
270 | * @return boolean |
||
271 | * @throws InvalidConfigException |
||
272 | * @throws \Exception |
||
273 | */ |
||
274 | 51 | protected function setUpBaseOrganization($models) |
|
275 | { |
||
276 | 51 | $model = null; |
|
277 | 51 | $associatedModels = []; |
|
278 | 51 | if (is_array($models)) { |
|
279 | 2 | if (!array_key_exists(0, $models)) { |
|
280 | 2 | throw new InvalidConfigException('Invalid Organization Model.'); |
|
281 | } |
||
282 | $model = $models[0]; |
||
283 | $associatedModels = array_key_exists('associatedModels', $models) ? $models['associatedModels'] : []; |
||
284 | 50 | } elseif ($models instanceof $this->organizationClass) { |
|
285 | 50 | $model = $models; |
|
286 | } |
||
287 | 50 | $result = $model->register($associatedModels); |
|
288 | 50 | if ($result instanceof \Exception) { |
|
289 | throw $result; |
||
290 | } |
||
291 | 50 | if ($result !== true) { |
|
292 | throw new \Exception('Failed to set up.'); |
||
293 | } |
||
294 | 50 | return true; |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * Create organization. |
||
299 | * @param string $name |
||
300 | * @param Organization $parent |
||
301 | * @param string $nickname |
||
302 | * @param string $gravatar_type |
||
303 | * @param string $gravatar |
||
304 | * @param string $timezone |
||
305 | * @param string $description |
||
306 | * @return Organization |
||
307 | */ |
||
308 | 50 | public function createOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '') |
|
309 | { |
||
310 | 50 | return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description); |
|
311 | } |
||
312 | |||
313 | /** |
||
314 | * Create department. |
||
315 | * @param string $name |
||
316 | * @param Organization $parent |
||
317 | * @param string $nickname |
||
318 | * @param string $gravatar_type |
||
319 | * @param string $gravatar |
||
320 | * @param string $timezone |
||
321 | * @param string $description |
||
322 | * @return Organization |
||
323 | */ |
||
324 | 18 | public function createDepartment($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '') |
|
325 | { |
||
326 | 18 | return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description, Organization::TYPE_DEPARTMENT); |
|
327 | } |
||
328 | |||
329 | /** |
||
330 | * Create Base Organization. |
||
331 | * @param string $name |
||
332 | * @param Organization $parent |
||
333 | * @param string $nickname |
||
334 | * @param integer $gravatar_type |
||
335 | * @param string $gravatar |
||
336 | * @param string $timezone |
||
337 | * @param string $description |
||
338 | * @param integer $type |
||
339 | * @return Organization |
||
340 | * @throws InvalidParamException throw if setting parent failed. Possible reasons include: |
||
341 | * - The parent is itself. |
||
342 | * - The parent has already been its ancestor. |
||
343 | * - The current organization has reached the limit of ancestors. |
||
344 | */ |
||
345 | 50 | protected function createBaseOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '', $type = Organization::TYPE_ORGANIZATION) |
|
346 | { |
||
347 | 50 | $class = $this->organizationClass; |
|
348 | $profileConfig = [ |
||
349 | 50 | 'name' => $name, |
|
350 | 50 | 'nickname' => $nickname, |
|
351 | 50 | 'gravatar_type' => $gravatar_type, |
|
352 | 50 | 'gravatar' => $gravatar, |
|
353 | 50 | 'timezone' => $timezone, |
|
354 | 50 | 'description' => $description, |
|
355 | ]; |
||
356 | 50 | $organization = new $class(['type' => $type, 'creatorModel' => $this, 'profileConfig' => $profileConfig]); |
|
357 | 50 | if (empty($parent)) { |
|
358 | 50 | $organization->setNullParent(); |
|
359 | 18 | } elseif ($organization->setParent($parent) === false) { |
|
360 | throw new InvalidParamException("Failed to set parent."); |
||
361 | } |
||
362 | 50 | return $organization; |
|
363 | } |
||
364 | |||
365 | /** |
||
366 | * Revoke organization or department. |
||
367 | * @param Organization|string|integer $organization Organization or it's ID or GUID. |
||
368 | * @param boolean $revokeIfHasChildren True represents revoking organization if there are subordinates. |
||
369 | * @return boolean True if revocation is successful. |
||
370 | * @throws InvalidParamException throws if organization is invalid. |
||
371 | * @throws \Exception |
||
372 | * @throws RevokePreventedException throws if $revokeIfHasChildren is false, at the |
||
373 | * same time the current organization or department has subordinates. |
||
374 | * @throws @var:$organization@mtd:deregister |
||
375 | */ |
||
376 | 14 | public function revokeOrganization($organization, $revokeIfHasChildren = true) |
|
377 | { |
||
378 | 14 | if (!($organization instanceof $this->organizationClass)) |
|
379 | { |
||
380 | 2 | $class = $this->organizationClass; |
|
381 | 2 | $organization = $class::find()->guidOrId($organization)->one(); |
|
382 | } |
||
383 | 14 | if (!($organization instanceof $this->organizationClass)) { |
|
384 | throw new InvalidParamException('Invalid Organization.'); |
||
385 | } |
||
386 | 14 | if (!Yii::$app->authManager->checkAccess( |
|
387 | $this, |
||
388 | 14 | $organization->type == Organization::TYPE_ORGANIZATION ? (new RevokeOrganization)->name : (new RevokeDepartment)->name, |
|
389 | 14 | ['organization' => $organization])) { |
|
390 | 1 | throw new InvalidParamException("You do not have permission to revoke it."); |
|
391 | } |
||
392 | 13 | $transaction = Yii::$app->db->beginTransaction(); |
|
393 | try { |
||
394 | 13 | if (!$revokeIfHasChildren && ((int)($organization->getChildren()->count())) > 0) { |
|
395 | $type = $organization->isOrganization() ? "organization" : "department"; |
||
396 | throw new RevokePreventedException("The $type has children. Revoking prevented."); |
||
397 | } |
||
398 | 13 | $result = $organization->deregister(); |
|
399 | 13 | if ($result instanceof \Exception){ |
|
400 | throw $result; |
||
401 | } |
||
402 | 13 | if ($result !== true) { |
|
403 | throw new InvalidParamException("Failed to revoke."); |
||
404 | } |
||
405 | 13 | $transaction->commit(); |
|
406 | } catch (\Exception $ex) { |
||
407 | $transaction->rollBack(); |
||
408 | Yii::error($ex->getMessage(), __METHOD__); |
||
409 | throw $ex; |
||
410 | } |
||
411 | 13 | return true; |
|
412 | } |
||
413 | |||
414 | /** |
||
415 | * Check whether current user is organization or department creator. |
||
416 | * @param Organization $organization |
||
417 | * @return boolean True if current is organization or department creator. |
||
418 | */ |
||
419 | 29 | public function isOrganizationCreator($organization) |
|
420 | { |
||
421 | 29 | $member = $organization->getMember($this); |
|
422 | 29 | if (!$member) { |
|
423 | 2 | return false; |
|
424 | } |
||
425 | 29 | return $member->isCreator(); |
|
426 | } |
||
427 | |||
428 | /** |
||
429 | * Check whether current user is organization or department administrator. |
||
430 | * @param Organization $organization |
||
431 | * @return boolean True if current is organization or department administrator. |
||
432 | */ |
||
433 | 14 | public function isOrganizationAdministrator($organization) |
|
434 | { |
||
435 | 14 | $member = $organization->getMember($this); |
|
436 | 14 | if (!$member) { |
|
437 | 3 | return false; |
|
438 | } |
||
439 | 14 | return $member->isAdministrator(); |
|
440 | } |
||
441 | |||
442 | /** |
||
443 | * Attach events associated with organization. |
||
444 | */ |
||
445 | 52 | public function initOrganizationEvents() |
|
446 | { |
||
447 | 52 | $this->on(static::EVENT_BEFORE_DELETE, [$this, "onRevokeOrganizationsByCreator"]); |
|
0 ignored issues
–
show
It seems like
on() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
448 | 52 | } |
|
449 | |||
450 | /** |
||
451 | * Revoke Organization Event. |
||
452 | * It should be triggered when deleting (not deregistering). |
||
453 | * @param Event $event |
||
454 | */ |
||
455 | 22 | public function onRevokeOrganizationsByCreator($event) |
|
456 | { |
||
457 | 22 | $sender = $event->sender; |
|
458 | /* @var $sender static */ |
||
459 | 22 | $organizations = $this->creatorsAtOrganizations; |
|
460 | 22 | foreach ($organizations as $org) |
|
461 | { |
||
462 | 4 | $sender->revokeOrganization($org); |
|
463 | } |
||
464 | 22 | } |
|
465 | |||
466 | /** |
||
467 | * Check whether the current user has reached the upper limit of organizations. |
||
468 | * @return boolean the upper limit of organizations which current could be set up. |
||
469 | */ |
||
470 | 51 | public function hasReachedOrganizationLimit() |
|
471 | { |
||
472 | 51 | $remaining = $this->getRemainingOrganizationPlaces(); |
|
473 | 51 | if ($remaining === false) { |
|
474 | return false; |
||
475 | } |
||
476 | 51 | return $remaining <= 0; |
|
477 | } |
||
478 | |||
479 | /** |
||
480 | * Get the remaining places of organizations. |
||
481 | * @return bool|int False if no limit. |
||
482 | */ |
||
483 | 51 | public function getRemainingOrganizationPlaces() |
|
484 | { |
||
485 | 51 | $class = $this->organizationLimitClass; |
|
486 | 51 | if (empty($class)) { |
|
487 | return false; |
||
488 | } |
||
489 | 51 | $limit = $class::getLimit($this); |
|
490 | 51 | if ($limit === false) { |
|
491 | return false; |
||
492 | } |
||
493 | 51 | $count = (int)$this->getCreatorsAtOrganizationsOnly()->count(); |
|
494 | 51 | return $limit - $count; |
|
495 | } |
||
496 | } |
||
497 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()
as an abstract method to the trait will make sure it is available.