Completed
Push — master ( 684373...1ddbd7 )
by vistart
04:25
created

OrganizationController::actionSetUpDepartment()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 10
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 3
crap 12
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\console\controllers;
14
15
use rhosocial\user\User;
16
use rhosocial\organization\Organization;
17
use rhosocial\organization\rbac\permissions\SetUpOrganization;
18
use Yii;
19
use yii\console\Controller;
20
use yii\console\Exception;
21
22
/**
23
 * Organization commands.
24
 *
25
 * @version 1.0
26
 * @author vistart <[email protected]>
27
 */
28
class OrganizationController extends Controller
29
{
30
    public $userClass;
31
    public $organizationClass;
32
    public $defaultAction = 'show';  
33
34
    /**
35
     * Check user class.
36
     * @return User
37
     * @throws Exception throw if User is not an instance inherited from `\rhosocial\user\User`.
38
     */
39
    protected function checkUserClass()
40
    {
41
        $userClass = $this->userClass;
42
        if (!class_exists($userClass)) {
43
            throw new Exception('User Class Invalid.');
44
        }
45
        if (!((new $userClass()) instanceof User)) {
46
            throw new Exception('User Class(' . $userClass . ') does not inherited from `\rhosocial\user\User`.');
47
        }
48
        return $userClass;
49
    }
50
51
    /**
52
     * Get user from database.
53
     * @param User|string|integer $user User ID.
54
     * @return User
55
     */
56
    protected function getUser($user)
57
    {
58
        $userClass = $this->checkUserClass();
59
        if (is_numeric($user)) {
60
            $user = $userClass::find()->id($user)->one();
61
        } elseif (is_string($user) && strlen($user)) {
62
            $user = $userClass::find()->guid($user)->one();
63
        }
64
        if (!$user || $user->getIsNewRecord()) {
0 ignored issues
show
Bug introduced by
It seems like $user is not always an object, but can also be of type array|string. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
65
            throw new Exception('User Not Registered.');
66
        }
67
        return $user;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $user; (yii\db\ActiveRecord|array|string) is incompatible with the return type documented by rhosocial\organization\c...tionController::getUser of type rhosocial\user\User.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
68
    }
69
70
    /**
71
     * Check organization class.
72
     * @return Organization
73
     * @throws Exception throw if Organization is not an instance inherited from `\rhosocial\organization\Organization`.
74
     */
75
    protected function checkOrganizationClass()
76
    {
77
        $organizationClass = $this->organizationClass;
78
        if (!class_exists($organizationClass)) {
79
            throw new Exception('Organization Class Invalid.');
80
        }
81
        if (!((new $organizationClass()) instanceof Organization)) {
82
            throw new Exception('Organization Class(' . $organizationClass . ') does not inherited from `\rhosocial\organization\Organization`.');
83
        }
84
        return $organizationClass;
85
    }
86
87
    /**
88
     * Get organization.
89
     * @param Organization|string|integer $organization
90
     * @return Organization
91
     */
92
    protected function getOrganization($organization)
93
    {
94
        $organizationClass = $this->checkOrganizationClass();
95
        if (is_numeric($organization)) {
96
            $organization = $organizationClass::find()->id($organization)->one();
97
        } elseif (is_string($organization) && strlen($organization)) {
98
            $organization = $organizationClass::find()->guid($organization)->one();
99
        }
100
        if (!$organization || $organization->getIsNewRecord()) {
0 ignored issues
show
Bug introduced by
It seems like $organization is not always an object, but can also be of type array|string. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
101
            throw new Exception('Organization Not Set Up.');
102
        }
103
        return $organization;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $organization; (yii\db\ActiveRecord|array|string) is incompatible with the return type documented by rhosocial\organization\c...roller::getOrganization of type rhosocial\organization\Organization.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
104
    }
105
106
    /**
107
     * Assign SetUpOrganization permission.
108
     * @param User|string|integer $user
109
     * @return boolean
110
     */
111
    public function actionAssignSetUpOrganization($user)
112
    {
113
        $user = $this->getUser($user);
114
        $permission = new SetUpOrganization();
115
        try {
116
            $assignment = Yii::$app->authManager->assign($permission->name, $user);
117
        } catch (\yii\db\IntegrityException $ex) {
118
            echo "Failed to assign `" . $permission->name . "`.\n";
119
            echo "Maybe the permission has been assigned.\n";
120
            return false;
121
        }
122
        if ($assignment) {
123
            echo "`$permission->name`" . " assigned to User (" . $user->getID() . ") successfully.\n";
124
        } else {
125
            echo "Failed to assign `" . $permission->name . "`.\n";
126
        }
127
        return true;
128
    }
129
130
    /**
131
     * Show Organization Information.
132
     * @param Organization|string|integer $organization Organization's or department's ID.
133
     */
134
    public function actionShow($organization)
135
    {
136
        $organization = $this->getOrganization($organization);
137
        echo $organization->getID() . "\n";
138
    }
139
140
    /**
141
     * Set up organization.
142
     * @param User|string|integer $user Organization creator.
143
     * @param string $name
144
     */
145
    public function actionSetUpOrganization($user, $name)
146
    {
147
        $user = $this->getUser($user);
148
        try {
149
            $result = $user->setUpOrganization($name);
150
            if ($result !== true) {
151
                throw new Exception('Failed to set up.');
152
            }
153
        } catch (\Exception $ex) {
154
            throw new Exception($ex->getMessage());
155
        }
156
        echo "Organization Set Up:\n";
157
        return $this->actionShow($user->lastSetUpOrganization);
158
    }
159
160
    /**
161
     * Set up department.
162
     * @param User|string|integer $user Department creator.
163
     * @param string $name
164
     * @param Organization|string|integer $parent
165
     */
166
    public function actionSetUpDepartment($user, $name, $parent)
167
    {
168
        $user = $this->getUser($user);
169
        $parent = $this->getOrganization($parent);
170
        try {
171
            $result = $user->setUpDepartment($name, $parent);
172
            if ($result !== true) {
173
                throw new Exception('Failed to set up.');
174
            }
175
        } catch (\Exception $ex) {
176
            throw new Exception($ex->getMessage());
177
        }
178
        echo "Department Set Up:\n";
179
        return $this->actionShow($user->lastSetUpOrganization);
180
    }
181
182
    /**
183
     * Revoke organization.
184
     * @param Organization|string|integer $organization
185
     * @throws Exception
186
     */
187
    public function actionRevokeOrganization($organization)
188
    {
189
        $organization = $this->getOrganization($organization);
190
        $creator = $organization->creator;
191
        if (!$creator->revokeOrganization($organization)) {
192
            throw new Exception('Failed to revoke: ' . $organization->getID);
0 ignored issues
show
Documentation introduced by
The property getID does not exist on object<rhosocial\organization\Organization>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
193
        }
194
        echo "Organization ({$organization->getID()}) revoked.\n";
195
    }
196
197
    /**
198
     * Add administrator.
199
     * @param Organization|string|integer $organization
200
     * @param User|string|integer $user
201
     */
202
    public function actionAddAdministrator($organization, $user)
203
    {
204
        $organization = $this->getOrganization($organization);
205
        $user = $this->getUser($user);
206
        if (!$organization->addAdministrator($user)) {
207
            throw new Exception('Failed to add administrator.');
208
        }
209
        echo "User ({$user->getID()}) assigned administrator.\n";
210
    }
211
212
    /**
213
     * Remove administrator
214
     * @param Organization|string|integer $organization
215
     * @param User|string|integer $user
216
     * @param boolean $keepMember
217
     */
218
    public function actionRemoveAdministrator($organization, $user, $keepMember = "yes")
219
    {
220
        $keepMember = strtolower($keepMember) == "yes";
221
        $organization = $this->getOrganization($organization);
222
        $user = $this->getUser($user);
223
        $id = $user->getID();
224
        if (!$organization->removeAdministrator($user, $keepMember)) {
225
            throw new Exception('Failed to remove administrator.');
226
        }
227
        echo "Administrator ($id) removed.\n";
228
        echo ($keepMember) ? ("But he is still a member of it.\n") : ("At the same time, he was also removed from the organization.\n");
229
    }
230
231
    /**
232
     * Remove member.
233
     * @param Organization|string|intger $organization
234
     * @param User|string|integer $user
235
     */
236
    public function actionRemoveMember($organization, $user)
237
    {
238
        $organization = $this->getOrganization($organization);
239
        $user = $this->getUser($user);
240
        $id = $user->getID();
241
        if (!$organization->removeMember($user)) {
242
            throw new Exception('Failed to remove member.');
243
        }
244
        echo "Member ($id) removed.\n";
245
    }
246
}
247