Passed
Push — master ( a274db...6e4772 )
by vistart
03:53
created

UserOrganizationTrait   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 79.81%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 35
lcom 1
cbo 7
dl 0
loc 271
ccs 83
cts 104
cp 0.7981
rs 9
c 1
b 0
f 1

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getNoInitOrganization() 0 8 2
A getNoInitMember() 0 8 2
A getOfMembers() 0 4 1
A getAtOrganizations() 0 4 1
A setUpOrganization() 0 15 2
A setUpDepartment() 0 18 3
B setUpBaseOrganization() 0 15 5
A createOrganization() 0 4 1
A createDepartment() 0 4 1
B createBaseOrganization() 0 29 5
C revokeOrganization() 0 31 8
A isOrganizationCreator() 0 8 2
A isOrganizationAdministrator() 0 8 2
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\DepartmentCreator;
18
use rhosocial\organization\rbac\roles\OrganizationCreator;
19
use Yii;
20
use yii\base\InvalidConfigException;
21
use yii\base\InvalidParamException;
22
23
/**
24
 * @property string $guidAttribute GUID Attribute.
25
 * @property-read Member[] $ofMembers
26
 * @property-read Organization[] $atOrganizations
27
 *
28
 * @version 1.0
29
 * @author vistart <[email protected]>
30
 */
31
trait UserOrganizationTrait
32
{
33
    public $organizationClass = Organization::class;
34
    public $memberClass = Member::class;
35
    private $noInitOrganization;
36
    private $noInitMember;
37
    public $lastSetUpOrganization;
38
    /**
39
     * @return Organization
40
     */
41
    protected function getNoInitOrganization()
42
    {
43
        if (!$this->noInitOrganization) {
44
            $class = $this->organizationClass;
45
            $this->noInitOrganization = $class::buildNoInitModel();
46
        }
47
        return $this->noInitOrganization;
48
    }
49
    /**
50
     * @return Member
51
     */
52 17
    protected function getNoInitMember()
53
    {
54 17
        if (!$this->noInitMember) {
55 17
            $class = $this->memberClass;
56 17
            $this->noInitMember = $class::buildNoInitModel();
57
        }
58 17
        return $this->noInitMember;
59
    }
60
61
    /**
62
     * 
63
     * @return MemberQuery
64
     */
65 17
    public function getOfMembers()
66
    {
67 17
        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...
68
    }
69
70
    /**
71
     * 
72
     * @return OrganizationQuery
73
     */
74 8
    public function getAtOrganizations()
75
    {
76 8
        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...
77
    }
78
79
    /**
80
     * Set up organization.
81
     * @param string $name
82
     * @param Organization $parent
83
     * @param string $nickname
84
     * @param integer $gravatar_type
85
     * @param string $gravatar
86
     * @param string $timezone
87
     * @param string $description
88
     * @return boolean Whether indicate the setting-up succeeded or not.
89
     */
90 24
    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...
91
    {
92 24
        $transaction = Yii::$app->db->beginTransaction();
93
        try {
94 24
            $models = $this->createOrganization($name, $parent, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '');
95 24
            $this->setUpBaseOrganization($models);
96 23
            $transaction->commit();
97 1
        } catch (\Exception $ex) {
98 1
            $transaction->rollBack();
99 1
            Yii::error($ex->getMessage(), __METHOD__);
100 1
            throw $ex;
101
        }
102 23
        $this->lastSetUpOrganization = $models[0];
103 23
        return true;
104
    }
105
106
    /**
107
     * Set up organization.
108
     * @param string $name
109
     * @param Organization $parent
110
     * @param string $nickname
111
     * @param integer $gravatar_type
112
     * @param string $gravatar
113
     * @param string $timezone
114
     * @param string $description
115
     * @return boolean Whether indicate the setting-up succeeded or not.
116
     */
117 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...
118
    {
119 3
        if ($parent == null) {
120 1
            throw new InvalidConfigException('Invalid Parent Parameter.');
121
        }
122 2
        $transaction = Yii::$app->db->beginTransaction();
123
        try {
124 2
            $models = $this->createDepartment($name, $parent, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '');
125 2
            $this->setUpBaseOrganization($models);
126 1
            $transaction->commit();
127 1
        } catch (\Exception $ex) {
128 1
            $transaction->rollBack();
129 1
            Yii::error($ex->getMessage(), __METHOD__);
130 1
            throw $ex;
131
        }
132 1
        $this->lastSetUpOrganization = $models[0];
133 1
        return true;
134
    }
135
136
    /**
137
     * Set up base organization.
138
     * @param array $models
139
     * @return boolean
140
     * @throws InvalidConfigException
141
     * @throws \Exception
142
     */
143 24
    protected function setUpBaseOrganization($models)
144
    {
145 24
        if (!array_key_exists(0, $models) || !($models[0] instanceof Organization))
146
        {
147 2
            throw new InvalidConfigException('Invalid Organization Model.');
148
        }
149 23
        $result = $models[0]->register($models['associatedModels']);
150 23
        if ($result instanceof \Exception) {
151
            throw $result;
152
        }
153 23
        if ($result !== true) {
154
            throw new \Exception('Failed to set up.');
155
        }
156 23
        return true;
157
    }
158
159
    /**
160
     * Create organization.
161
     * @param string $name
162
     * @param Organization $parent
163
     * @param string $nickname
164
     * @param string $gravatar_type
165
     * @param string $gravatar
166
     * @param string $timezone
167
     * @param string $description
168
     * @return Organization
169
     */
170 23
    public function createOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
171
    {
172 23
        return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description);
173
    }
174
175
    /**
176
     * Create department.
177
     * @param string $name
178
     * @param Organization $parent
179
     * @param string $nickname
180
     * @param string $gravatar_type
181
     * @param string $gravatar
182
     * @param string $timezone
183
     * @param string $description
184
     * @return Organization
185
     */
186 1
    public function createDepartment($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '')
187
    {
188 1
        return $this->createBaseOrganization($name, $parent, $nickname, $gravatar_type, $gravatar, $timezone, $description, Organization::TYPE_DEPARTMENT);
189
    }
190
191
    /**
192
     * Create Base Organization.
193
     * @param string $name
194
     * @param Organization $parent
195
     * @param string $nickname
196
     * @param integer $gravatar_type
197
     * @param string $gravatar
198
     * @param string $timezone
199
     * @param string $description
200
     * @param integer $type
201
     * @return array This array contains two elements, the first is `Organization` or `Department` depends on `$type`.
202
     * The other is `associatedModels` array, contains two elements `Profile`(profile) and `Creator`(creator).
203
     * @throws InvalidParamException throw if setting parent failed. Possible reasons include:
204
     * - The parent is itself.
205
     * - The parent has already been its ancestor.
206
     * - The current organization has reached the limit of ancestors.
207
     */
208 23
    protected function createBaseOrganization($name, $parent = null, $nickname = '', $gravatar_type = 0, $gravatar = '', $timezone = 'UTC', $description = '', $type = Organization::TYPE_ORGANIZATION)
209
    {
210 23
        $class = $this->organizationClass;
211 23
        $organization = new $class(['type' => $type]);
212 23
        if (empty($parent)) {
213 23
            $organization->setNullParent();
214 4
        } elseif ($organization->setParent($parent) === false) {
215
            throw new InvalidParamException("Failed to set parent.");
216
        }
217
        /* @var $organization Organization */
218
        $profileConfig = [
219 23
            'name' => $name,
220 23
            'nickname' => $nickname,
221 23
            'gravatar_type' => $gravatar_type,
222 23
            'gravatar' => $gravatar,
223 23
            'timezone' => $timezone,
224 23
            'description' => $description,
225
        ];
226 23
        $profile = $organization->createProfile($profileConfig);
227 23
        $role = null;
228 23
        if ($type == Organization::TYPE_ORGANIZATION) {
229 23
            $role = new OrganizationCreator();
230 1
        } elseif ($type == Organization::TYPE_DEPARTMENT) {
231 1
            $role = new DepartmentCreator();
232
        }
233 23
        $member = $organization->createMemberModelWithUser($this);
234 23
        $member->assignRole($role);
0 ignored issues
show
Bug introduced by
It seems like $role defined by null on line 227 can also be of type null; however, rhosocial\organization\Member::assignRole() does only seem to accept object<rhosocial\user\rbac\Role>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
235 23
        return [0 => $organization, 'associatedModels' => ['profile' => $profile, 'creator'=> $member]];
236
    }
237
238
    /**
239
     * Revoke organization.
240
     * @param static|string|integer $organization
241
     * @param boolean $revokeIfHasChildren
242
     * @throws InvalidParamException throw if current user is not the creator of organization.
243
     */
244 1
    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...
245
    {
246 1
        if (!($organization instanceof $this->organizationClass))
247
        {
248
            $class = $this->organizationClass;
249
            if (is_int($organization)) {
250
                $organization = $class::find()->id($organization)->one();
251
            } elseif (is_string($organization)) {
252
                $organization = $class::find()->guid($organization)->one();
253
            }
254
        }
255 1
        if (!$this->isOrganizationCreator($organization)) {
256
            throw new InvalidParamException('You are not the creator of the this organization and have no right to revoke it.');
257
        }
258 1
        $transaction = Yii::$app->db->beginTransaction();
259
        try {
260 1
            $result = $organization->deregister();
261 1
            if ($result instanceof \Exception){
262
                throw $result;
263
            }
264 1
            if ($result !== true) {
265
                throw new InvalidParamException();
266
            }
267 1
            $transaction->commit();
268
        } catch (\Exception $ex) {
269
            $transaction->rollBack();
270
            Yii::error($ex->getMessage(), __METHOD__);
271
            throw $ex;
272
        }
273 1
        return true;
274
    }
275
276
    /**
277
     * 
278
     * @param Organization $organization
279
     */
280 1
    public function isOrganizationCreator($organization)
281
    {
282 1
        $member = $organization->getMember($this);
283 1
        if (!$member) {
284
            return false;
285
        }
286 1
        return $member->isCreator();
287
    }
288
289
    /**
290
     * 
291
     * @param Organization $organization
292
     */
293 2
    public function isOrganizationAdministrator($organization)
294
    {
295 2
        $member = $organization->getMember($this);
296 2
        if (!$member) {
297 2
            return false;
298
        }
299 2
        return $member->isAdministrator();
300
    }
301
}
302