Passed
Push — master ( ebfd49...ed3d70 )
by vistart
03:53
created

UserOrganizationTrait::revokeOrganization()   D

Complexity

Conditions 9
Paths 28

Size

Total Lines 34
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 12.4077

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 15
cts 23
cp 0.6522
rs 4.909
c 0
b 0
f 0
cc 9
eloc 24
nc 28
nop 2
crap 12.4077
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\roles\DepartmentAdmin;
18
use rhosocial\organization\rbac\roles\DepartmentCreator;
19
use rhosocial\organization\rbac\roles\OrganizationAdmin;
20
use rhosocial\organization\rbac\roles\OrganizationCreator;
21
use Yii;
22
use yii\base\InvalidConfigException;
23
use yii\base\InvalidParamException;
24
25
/**
26
 * @property string $guidAttribute GUID Attribute.
27
 * @property-read Member[] $ofMembers
28
 * @property-read Organization[] $atOrganizations
29
 * @property-read Organization[] $creatorsAtOrganizations
30
 * @property-read Organization[] $administratorsAtOrganizations
31
 *
32
 * @version 1.0
33
 * @author vistart <[email protected]>
34
 */
35
trait UserOrganizationTrait
36
{
37
    public $organizationClass = Organization::class;
38
    public $memberClass = Member::class;
39
    private $noInitOrganization;
40
    private $noInitMember;
41
    public $lastSetUpOrganization;
42
    /**
43
     * @return Organization
44
     */
45
    protected function getNoInitOrganization()
46
    {
47
        if (!$this->noInitOrganization) {
48
            $class = $this->organizationClass;
49
            $this->noInitOrganization = $class::buildNoInitModel();
50
        }
51
        return $this->noInitOrganization;
52
    }
53
    /**
54
     * @return Member
55
     */
56 25
    protected function getNoInitMember()
57
    {
58 25
        if (!$this->noInitMember) {
59 25
            $class = $this->memberClass;
60 25
            $this->noInitMember = $class::buildNoInitModel();
61
        }
62 25
        return $this->noInitMember;
63
    }
64
65
    /**
66
     * 
67
     * @return MemberQuery
68
     */
69 25
    public function getOfMembers()
70
    {
71 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...
72
    }
73
74
    /**
75
     * 
76
     * @return MemberQuery
77
     */
78 2
    public function getOfCreators()
79
    {
80 2
        return $this->getOfMembers()->andWhere(['role' => [(new DepartmentCreator)->name, (new OrganizationCreator)->name]]);
81
    }
82
83
    /**
84
     * 
85
     * @return MemberQuery
86
     */
87 2
    public function getOfAdministrators()
88
    {
89 2
        return $this->getOfMembers()->andWhere(['role' => [(new DepartmentAdmin)->name, (new OrganizationAdmin)->name]]);
90
    }
91
92
    /**
93
     * 
94
     * @return OrganizationQuery
95
     */
96 10
    public function getAtOrganizations()
97
    {
98 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...
99
    }
100
101
    /**
102
     * 
103
     * @return OrganizationQuery
104
     */
105 2
    public function getCreatorsAtOrganizations()
106
    {
107 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...
108
    }
109
110
    /**
111
     * 
112
     * @return OrganizationQuery
113
     */
114 2
    public function getAdministratorsAtOrganizations()
115
    {
116 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...
117
    }
118
119
    /**
120
     * Set up organization.
121
     * @param string $name
122
     * @param Organization $parent
123
     * @param string $nickname
124
     * @param integer $gravatar_type
125
     * @param string $gravatar
126
     * @param string $timezone
127
     * @param string $description
128
     * @return boolean Whether indicate the setting-up succeeded or not.
129
     */
130 32
    public function setUpOrganization($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...
131
    {
132 32
        $transaction = Yii::$app->db->beginTransaction();
133
        try {
134 32
            $models = $this->createOrganization($name, $parent, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '');
135 32
            $this->setUpBaseOrganization($models);
136 31
            $transaction->commit();
137 1
        } catch (\Exception $ex) {
138 1
            $transaction->rollBack();
139 1
            Yii::error($ex->getMessage(), __METHOD__);
140 1
            throw $ex;
141
        }
142 31
        $this->lastSetUpOrganization = is_array($models) ? $models[0] : $models;
143 31
        return true;
144
    }
145
146
    /**
147
     * Set up organization.
148
     * @param string $name
149
     * @param Organization $parent
150
     * @param string $nickname
151
     * @param integer $gravatar_type
152
     * @param string $gravatar
153
     * @param string $timezone
154
     * @param string $description
155
     * @return boolean Whether indicate the setting-up succeeded or not.
156
     */
157 3
    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...
158
    {
159 3
        if ($parent == null) {
160 1
            throw new InvalidConfigException('Invalid Parent Parameter.');
161
        }
162 2
        $transaction = Yii::$app->db->beginTransaction();
163
        try {
164 2
            $models = $this->createDepartment($name, $parent, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '');
165 2
            $this->setUpBaseOrganization($models);
166 1
            $transaction->commit();
167 1
        } catch (\Exception $ex) {
168 1
            $transaction->rollBack();
169 1
            Yii::error($ex->getMessage(), __METHOD__);
170 1
            throw $ex;
171
        }
172 1
        $this->lastSetUpOrganization = is_array($models) ? $models[0] : $models;
173 1
        return true;
174
    }
175
176
    /**
177
     * Set up base organization.
178
     * @param Organization $models
179
     * @return boolean
180
     * @throws InvalidConfigException
181
     * @throws \Exception
182
     */
183 32
    protected function setUpBaseOrganization($models)
184
    {
185 32
        $model = null;
186 32
        $associatedModels = [];
187 32
        if (is_array($models)) {
188 2
            if (!array_key_exists(0, $models)) {
189 2
                throw new InvalidConfigException('Invalid Organization Model.');
190
            }
191
            $model = $models[0];
192
            $associatedModels = array_key_exists('associatedModels', $models) ? $models['associatedModels'] : [];
193
        } elseif ($models instanceof Organization) {
194 31
            $model = $models;
195
        }
196 31
        $result = $model->register($associatedModels);
197 31
        if ($result instanceof \Exception) {
198
            throw $result;
199
        }
200 31
        if ($result !== true) {
201
            throw new \Exception('Failed to set up.');
202
        }
203 31
        return true;
204
    }
205
206
    /**
207
     * Create organization.
208
     * @param string $name
209
     * @param Organization $parent
210
     * @param string $nickname
211
     * @param string $gravatar_type
212
     * @param string $gravatar
213
     * @param string $timezone
214
     * @param string $description
215
     * @return Organization
216
     */
217 31
    public function createOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
218
    {
219 31
        return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description);
220
    }
221
222
    /**
223
     * Create department.
224
     * @param string $name
225
     * @param Organization $parent
226
     * @param string $nickname
227
     * @param string $gravatar_type
228
     * @param string $gravatar
229
     * @param string $timezone
230
     * @param string $description
231
     * @return Organization
232
     */
233 1
    public function createDepartment($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
234
    {
235 1
        return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description, Organization::TYPE_DEPARTMENT);
236
    }
237
238
    /**
239
     * Create Base Organization.
240
     * @param string $name
241
     * @param Organization $parent
242
     * @param string $nickname
243
     * @param integer $gravatar_type
244
     * @param string $gravatar
245
     * @param string $timezone
246
     * @param string $description
247
     * @param integer $type
248
     * @return Organization
249
     * @throws InvalidParamException throw if setting parent failed. Possible reasons include:
250
     * - The parent is itself.
251
     * - The parent has already been its ancestor.
252
     * - The current organization has reached the limit of ancestors.
253
     */
254 31
    protected function createBaseOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '', $type = Organization::TYPE_ORGANIZATION)
255
    {
256 31
        $class = $this->organizationClass;
257
        $profileConfig = [
258 31
            'name' => $name,
259 31
            'nickname' => $nickname,
260 31
            'gravatar_type' => $gravatar_type,
261 31
            'gravatar' => $gravatar,
262 31
            'timezone' => $timezone,
263 31
            'description' => $description,
264
        ];
265 31
        $organization = new $class(['type' => $type, 'creatorModel' => $this, 'profileConfig' => $profileConfig]);
266 31
        if (empty($parent)) {
267 31
            $organization->setNullParent();
268 4
        } elseif ($organization->setParent($parent) === false) {
269
            throw new InvalidParamException("Failed to set parent.");
270
        }
271 31
        return $organization;
272
    }
273
274
    /**
275
     * Revoke organization.
276
     * @param static|string|integer $organization
277
     * @param boolean $revokeIfHasChildren
278
     * @throws InvalidParamException throw if current user is not the creator of organization.
279
     */
280 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...
281
    {
282 8
        if (!($organization instanceof $this->organizationClass))
283
        {
284 2
            $class = $this->organizationClass;
285 2
            if (is_numeric($organization)) {
286 1
                $organization = $class::find()->id($organization)->one();
287 1
            } elseif (is_string($organization)) {
288 1
                $organization = $class::find()->guid($organization)->one();
289
            }
290
        }
291 8
        if (!$organization) {
292
            throw new InvalidParamException('Invalid Organization.');
293
        }
294 8
        if (!$this->isOrganizationCreator($organization)) {
295
            throw new InvalidParamException('You are not the creator of the this organization and have no right to revoke it.');
296
        }
297 8
        $transaction = Yii::$app->db->beginTransaction();
298
        try {
299 8
            $result = $organization->deregister();
300 8
            if ($result instanceof \Exception){
301
                throw $result;
302
            }
303 8
            if ($result !== true) {
304
                throw new InvalidParamException();
305
            }
306 8
            $transaction->commit();
307
        } catch (\Exception $ex) {
308
            $transaction->rollBack();
309
            Yii::error($ex->getMessage(), __METHOD__);
310
            throw $ex;
311
        }
312 8
        return true;
313
    }
314
315
    /**
316
     * 
317
     * @param Organization $organization
318
     */
319 8
    public function isOrganizationCreator($organization)
320
    {
321 8
        $member = $organization->getMember($this);
322 8
        if (!$member) {
323 1
            return false;
324
        }
325 8
        return $member->isCreator();
326
    }
327
328
    /**
329
     * 
330
     * @param Organization $organization
331
     */
332 2
    public function isOrganizationAdministrator($organization)
333
    {
334 2
        $member = $organization->getMember($this);
335 2
        if (!$member) {
336 2
            return false;
337
        }
338 2
        return $member->isAdministrator();
339
    }
340
}
341