Passed
Push — master ( 4533bd...a8bd66 )
by vistart
04:24
created

UserOrganizationTrait::createBaseOrganization()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3.0032

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 13
cts 14
cp 0.9286
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 15
nc 3
nop 8
crap 3.0032

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\organization\queries\MemberQuery;
16
use rhosocial\organization\queries\OrganizationQuery;
17
use rhosocial\organization\rbac\permissions\SetUpOrganization;
18
use rhosocial\organization\rbac\permissions\SetUpDepartment;
19
use rhosocial\organization\rbac\permissions\RevokeOrganization;
20
use rhosocial\organization\rbac\permissions\RevokeDepartment;
21
use rhosocial\organization\rbac\roles\DepartmentAdmin;
22
use rhosocial\organization\rbac\roles\DepartmentCreator;
23
use rhosocial\organization\rbac\roles\OrganizationAdmin;
24
use rhosocial\organization\rbac\roles\OrganizationCreator;
25
use Yii;
26
use yii\base\InvalidConfigException;
27
use yii\base\InvalidParamException;
28
29
/**
30
 * @property string $guidAttribute GUID Attribute.
31
 * @property-read Member[] $ofMembers
32
 * @property-read Organization[] $atOrganizations
33
 * @property-read Organization[] $creatorsAtOrganizations
34
 * @property-read Organization[] $administratorsAtOrganizations
35
 *
36
 * @version 1.0
37
 * @author vistart <[email protected]>
38
 */
39
trait UserOrganizationTrait
40
{
41
    public $organizationClass = Organization::class;
42
    public $memberClass = Member::class;
43
    private $noInitOrganization;
44
    private $noInitMember;
45
    public $lastSetUpOrganization;
46
    /**
47
     * @return Organization
48
     */
49
    protected function getNoInitOrganization()
50
    {
51
        if (!$this->noInitOrganization) {
52
            $class = $this->organizationClass;
53
            $this->noInitOrganization = $class::buildNoInitModel();
54
        }
55
        return $this->noInitOrganization;
56
    }
57
    /**
58
     * @return Member
59
     */
60 25
    protected function getNoInitMember()
61
    {
62 25
        if (!$this->noInitMember) {
63 25
            $class = $this->memberClass;
64 25
            $this->noInitMember = $class::buildNoInitModel();
65
        }
66 25
        return $this->noInitMember;
67
    }
68
69
    /**
70
     * 
71
     * @return MemberQuery
72
     */
73 25
    public function getOfMembers()
74
    {
75 25
        return $this->hasMany($this->memberClass, [$this->getNoInitMember()->memberAttribute => $this->guidAttribute])->inverseOf('memberUser');
0 ignored issues
show
Bug introduced by
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 Idable provides a method equalsId that in turn relies on the method getId(). 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.

Loading history...
76
    }
77
78
    /**
79
     * 
80
     * @return MemberQuery
81
     */
82 2
    public function getOfCreators()
83
    {
84 2
        return $this->getOfMembers()->andWhere(['role' => [(new DepartmentCreator)->name, (new OrganizationCreator)->name]]);
85
    }
86
87
    /**
88
     * 
89
     * @return MemberQuery
90
     */
91 2
    public function getOfAdministrators()
92
    {
93 2
        return $this->getOfMembers()->andWhere(['role' => [(new DepartmentAdmin)->name, (new OrganizationAdmin)->name]]);
94
    }
95
96
    /**
97
     * 
98
     * @return OrganizationQuery
99
     */
100 10
    public function getAtOrganizations()
101
    {
102 10
        return $this->hasMany($this->organizationClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->via('ofMembers');
0 ignored issues
show
Bug introduced by
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 Idable provides a method equalsId that in turn relies on the method getId(). 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.

Loading history...
103
    }
104
105
    /**
106
     * 
107
     * @return OrganizationQuery
108
     */
109 2
    public function getCreatorsAtOrganizations()
110
    {
111 2
        return $this->hasMany($this->organizationClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->via('ofCreators');
0 ignored issues
show
Bug introduced by
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 Idable provides a method equalsId that in turn relies on the method getId(). 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.

Loading history...
112
    }
113
114
    /**
115
     * 
116
     * @return OrganizationQuery
117
     */
118 2
    public function getAdministratorsAtOrganizations()
119
    {
120 2
        return $this->hasMany($this->organizationClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->via('ofAdministrators');
0 ignored issues
show
Bug introduced by
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 Idable provides a method equalsId that in turn relies on the method getId(). 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.

Loading history...
121
    }
122
123
    /**
124
     * Set up organization.
125
     * @param string $name
126
     * @param string $nickname
127
     * @param integer $gravatar_type
128
     * @param string $gravatar
129
     * @param string $timezone
130
     * @param string $description
131
     * @return boolean Whether indicate the setting-up succeeded or not.
132
     */
133 32
    public function setUpOrganization($name, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
0 ignored issues
show
Unused Code introduced by
The parameter $nickname is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $gravatar_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $gravatar is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $timezone is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $description is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
134
    {
135 32
        $accessChecker = Yii::$app->authManager;
136 32
        if (!$accessChecker->checkAccess($this, (new SetUpOrganization)->name)) {
137
            throw new InvalidParamException("You do not have permission to set up organization.");
138
        }
139 32
        $transaction = Yii::$app->db->beginTransaction();
140
        try {
141 32
            $models = $this->createOrganization($name, null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '');
142 32
            $this->setUpBaseOrganization($models);
143 31
            $transaction->commit();
144 1
        } catch (\Exception $ex) {
145 1
            $transaction->rollBack();
146 1
            Yii::error($ex->getMessage(), __METHOD__);
147 1
            throw $ex;
148
        }
149 31
        $this->lastSetUpOrganization = is_array($models) ? $models[0] : $models;
150 31
        return true;
151
    }
152
153
    /**
154
     * Set up organization.
155
     * @param string $name
156
     * @param Organization $parent
157
     * @param string $nickname
158
     * @param integer $gravatar_type
159
     * @param string $gravatar
160
     * @param string $timezone
161
     * @param string $description
162
     * @return boolean Whether indicate the setting-up succeeded or not.
163
     */
164 5
    public function setUpDepartment($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
0 ignored issues
show
Unused Code introduced by
The parameter $nickname is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $gravatar_type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $gravatar is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $timezone is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $description is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
    {
166 5
        if (!($parent instanceof Organization)) {
167 1
            throw new InvalidParamException('Invalid Parent Parameter.');
168
        }
169 4
        $accessChecker = Yii::$app->authManager;
170 4
        if (!$accessChecker->checkAccess($this, (new SetUpDepartment)->name)) {
171
            throw new InvalidParamException("You do not have permission to set up department.");
172
        }
173 4
        $transaction = Yii::$app->db->beginTransaction();
174
        try {
175 4
            $models = $this->createDepartment($name, $parent, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '');
176 4
            $this->setUpBaseOrganization($models);
177 3
            $transaction->commit();
178 1
        } catch (\Exception $ex) {
179 1
            $transaction->rollBack();
180 1
            Yii::error($ex->getMessage(), __METHOD__);
181 1
            throw $ex;
182
        }
183 3
        $this->lastSetUpOrganization = is_array($models) ? $models[0] : $models;
184 3
        return true;
185
    }
186
187
    /**
188
     * Set up base organization.
189
     * @param Organization $models
190
     * @return boolean
191
     * @throws InvalidConfigException
192
     * @throws \Exception
193
     */
194 32
    protected function setUpBaseOrganization($models)
195
    {
196 32
        $model = null;
197 32
        $associatedModels = [];
198 32
        if (is_array($models)) {
199 2
            if (!array_key_exists(0, $models)) {
200 2
                throw new InvalidConfigException('Invalid Organization Model.');
201
            }
202
            $model = $models[0];
203
            $associatedModels = array_key_exists('associatedModels', $models) ? $models['associatedModels'] : [];
204
        } elseif ($models instanceof Organization) {
205 31
            $model = $models;
206
        }
207 31
        $result = $model->register($associatedModels);
208 31
        if ($result instanceof \Exception) {
209
            throw $result;
210
        }
211 31
        if ($result !== true) {
212
            throw new \Exception('Failed to set up.');
213
        }
214 31
        return true;
215
    }
216
217
    /**
218
     * Create organization.
219
     * @param string $name
220
     * @param Organization $parent
221
     * @param string $nickname
222
     * @param string $gravatar_type
223
     * @param string $gravatar
224
     * @param string $timezone
225
     * @param string $description
226
     * @return Organization
227
     */
228 31
    public function createOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
229
    {
230 31
        return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description);
231
    }
232
233
    /**
234
     * Create department.
235
     * @param string $name
236
     * @param Organization $parent
237
     * @param string $nickname
238
     * @param string $gravatar_type
239
     * @param string $gravatar
240
     * @param string $timezone
241
     * @param string $description
242
     * @return Organization
243
     */
244 3
    public function createDepartment($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
245
    {
246 3
        return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description, Organization::TYPE_DEPARTMENT);
247
    }
248
249
    /**
250
     * Create Base Organization.
251
     * @param string $name
252
     * @param Organization $parent
253
     * @param string $nickname
254
     * @param integer $gravatar_type
255
     * @param string $gravatar
256
     * @param string $timezone
257
     * @param string $description
258
     * @param integer $type
259
     * @return Organization
260
     * @throws InvalidParamException throw if setting parent failed. Possible reasons include:
261
     * - The parent is itself.
262
     * - The parent has already been its ancestor.
263
     * - The current organization has reached the limit of ancestors.
264
     */
265 31
    protected function createBaseOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '', $type = Organization::TYPE_ORGANIZATION)
266
    {
267 31
        $class = $this->organizationClass;
268
        $profileConfig = [
269 31
            'name' => $name,
270 31
            'nickname' => $nickname,
271 31
            'gravatar_type' => $gravatar_type,
272 31
            'gravatar' => $gravatar,
273 31
            'timezone' => $timezone,
274 31
            'description' => $description,
275
        ];
276 31
        $organization = new $class(['type' => $type, 'creatorModel' => $this, 'profileConfig' => $profileConfig]);
277 31
        if (empty($parent)) {
278 31
            $organization->setNullParent();
279 3
        } elseif ($organization->setParent($parent) === false) {
280
            throw new InvalidParamException("Failed to set parent.");
281
        }
282 31
        return $organization;
283
    }
284
285
    /**
286
     * Revoke organization or department.
287
     * @param static|string|integer $organization
288
     * @param boolean $revokeIfHasChildren
289
     * @throws InvalidParamException throw if current user is not the creator of organization.
290
     */
291 8
    public function revokeOrganization($organization, $revokeIfHasChildren = false)
0 ignored issues
show
Unused Code introduced by
The parameter $revokeIfHasChildren is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
292
    {
293 8
        if (!($organization instanceof $this->organizationClass))
294
        {
295 2
            $class = $this->organizationClass;
296 2
            if (is_numeric($organization)) {
297 1
                $organization = $class::find()->id($organization)->one();
298 1
            } elseif (is_string($organization)) {
299 1
                $organization = $class::find()->guid($organization)->one();
300
            }
301
        }
302 8
        if (!($organization instanceof Organization)) {
303
            throw new InvalidParamException('Invalid Organization.');
304
        }
305 8
        $accessChecker = Yii::$app->authManager;
306 8
        if ($organization->type == Organization::TYPE_ORGANIZATION) {
307 8
            if (!$accessChecker->checkAccess($this, (new RevokeOrganization)->name, [
308 8
                'organization' => $organization,
309
            ])) {
310 8
                throw new InvalidParamException("You do not have permission to revoke it.");
311
            }
312
        } elseif ($organization->type == Organization::TYPE_DEPARTMENT) {
313
            if (!$accessChecker->checkAccess($this, (new RevokeDepartment)-name, [
314
                'organization' => $organization,
315
            ])) {
316
                throw new InvalidParamException("You do not have permission to revoke it.");
317
            }
318
        }
319 8
        $transaction = Yii::$app->db->beginTransaction();
320
        try {
321 8
            $result = $organization->deregister();
322 8
            if ($result instanceof \Exception){
323
                throw $result;
324
            }
325 8
            if ($result !== true) {
326
                throw new InvalidParamException("Failed to revoke.");
327
            }
328 8
            $transaction->commit();
329
        } catch (\Exception $ex) {
330
            $transaction->rollBack();
331
            Yii::error($ex->getMessage(), __METHOD__);
332
            throw $ex;
333
        }
334 8
        return true;
335
    }
336
337
    /**
338
     * 
339
     * @param Organization $organization
340
     */
341 8
    public function isOrganizationCreator($organization)
342
    {
343 8
        $member = $organization->getMember($this);
344 8
        if (!$member) {
345 1
            return false;
346
        }
347 8
        return $member->isCreator();
348
    }
349
350
    /**
351
     * 
352
     * @param Organization $organization
353
     */
354 2
    public function isOrganizationAdministrator($organization)
355
    {
356 2
        $member = $organization->getMember($this);
357 2
        if (!$member) {
358 2
            return false;
359
        }
360 2
        return $member->isAdministrator();
361
    }
362
}
363