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\traits\SelfBlameableTrait; |
16
|
|
|
use rhosocial\base\models\queries\BaseUserQuery; |
17
|
|
|
use rhosocial\user\User; |
18
|
|
|
use rhosocial\organization\queries\MemberQuery; |
19
|
|
|
use rhosocial\organization\queries\DepartmentQuery; |
20
|
|
|
use rhosocial\organization\queries\OrganizationQuery; |
21
|
|
|
use Yii; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Base Organization. |
25
|
|
|
* This class is an abstract class that can not be instantiated directly. |
26
|
|
|
* You can use [[Organization]] or [[Department]] instead. |
27
|
|
|
* |
28
|
|
|
* @method Member createMember(array $config) Create member who is subordinate to this. |
29
|
|
|
* @property integer $type Whether indicate this instance is an organization or a department. |
30
|
|
|
|
31
|
|
|
* @version 1.0 |
32
|
|
|
* @author vistart <[email protected]> |
33
|
|
|
*/ |
34
|
|
|
class Organization extends User |
35
|
|
|
{ |
36
|
|
|
use SelfBlameableTrait; |
37
|
|
|
|
38
|
|
|
const TYPE_ORGANIZATION = 1; |
39
|
|
|
const TYPE_DEPARTMENT = 2; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var boolean Organization does not need password and corresponding features. |
43
|
|
|
*/ |
44
|
|
|
public $passwordHashAttribute = false; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var boolean Organization does not need password and corresponding features. |
48
|
|
|
*/ |
49
|
|
|
public $passwordResetTokenAttribute = false; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var boolean Organization does not need password and corresponding features. |
53
|
|
|
*/ |
54
|
|
|
public $passwordHistoryClass = false; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var boolean Organization does not need source. |
58
|
|
|
*/ |
59
|
|
|
public $sourceAttribute = false; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var boolean Organization does not need auth key. |
63
|
|
|
*/ |
64
|
|
|
public $authKeyAttribute = false; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var boolean Organization does not need access token. |
68
|
|
|
*/ |
69
|
|
|
public $accessTokenAttribute = false; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* |
73
|
|
|
* @var boolean Organization does not need login log. |
74
|
|
|
*/ |
75
|
|
|
public $loginLogClass = false; |
76
|
|
|
|
77
|
|
|
public $profileClass = Profile::class; |
78
|
|
|
|
79
|
|
|
public $memberClass = Member::class; |
80
|
|
|
private $noInitMember; |
81
|
|
|
/** |
82
|
|
|
* @return Member |
83
|
|
|
*/ |
84
|
|
|
protected function getNoInitMember() |
85
|
|
|
{ |
86
|
|
|
if (!$this->noInitMember) { |
87
|
|
|
$class = $this->memberClass; |
88
|
|
|
$this->noInitMember = $class::buildNoInitMember(); |
89
|
|
|
} |
90
|
|
|
return $this->noInitMember; |
91
|
|
|
} |
92
|
|
|
|
93
|
12 |
|
public function init() |
94
|
|
|
{ |
95
|
12 |
|
$this->parentAttribute = 'parent_guid'; |
96
|
12 |
|
if (class_exists($this->memberClass)) { |
97
|
12 |
|
$this->addSubsidiaryClass('Member', ['class' => Member::class]); |
98
|
12 |
|
} |
99
|
12 |
|
if ($this->skipInit) { |
100
|
12 |
|
return; |
101
|
|
|
} |
102
|
12 |
|
parent::init(); |
103
|
12 |
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @inheritdoc |
107
|
|
|
*/ |
108
|
|
|
public function attributeLabels() |
109
|
|
|
{ |
110
|
|
|
return [ |
111
|
|
|
'guid' => Yii::t('app', 'GUID'), |
112
|
|
|
'id' => Yii::t('app', 'ID'), |
113
|
|
|
'ip' => Yii::t('app', 'IP'), |
114
|
|
|
'ip_type' => Yii::t('app', 'IP Address Type'), |
115
|
|
|
'parent' => Yii::t('app', 'Parent'), |
116
|
|
|
'created_at' => Yii::t('app', 'Create Time'), |
117
|
|
|
'updated_at' => Yii::t('app', 'Update Time'), |
118
|
|
|
'status' => Yii::t('app', 'Status'), |
119
|
|
|
'type' => Yii::t('app', 'Type'), |
120
|
|
|
]; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @inheritdoc |
125
|
|
|
*/ |
126
|
12 |
|
public static function tableName() |
127
|
|
|
{ |
128
|
12 |
|
return '{{%organization}}'; |
129
|
|
|
} |
130
|
|
|
|
131
|
11 |
|
protected function getTypeRules() |
132
|
|
|
{ |
133
|
|
|
return [ |
134
|
11 |
|
['type', 'default', 'value' => static::TYPE_ORGANIZATION], |
135
|
11 |
|
['type', 'required'], |
136
|
11 |
|
['type', 'in', 'range' => [static::TYPE_ORGANIZATION, static::TYPE_DEPARTMENT]], |
137
|
11 |
|
]; |
138
|
|
|
} |
139
|
|
|
|
140
|
11 |
|
public function rules() |
141
|
|
|
{ |
142
|
11 |
|
return array_merge(parent::rules(), $this->getTypeRules(), $this->getSelfBlameableRules()); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Get Member Query. |
147
|
|
|
* @return MemberQuery |
148
|
|
|
*/ |
149
|
|
|
public function getMembers() |
150
|
|
|
{ |
151
|
|
|
return $this->hasMany($this->memberClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->inverseOf('organization'); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Get organization member users' query. |
156
|
|
|
* @return BaseUserQuery |
157
|
|
|
*/ |
158
|
|
|
public function getMemberUsers() |
159
|
|
|
{ |
160
|
|
|
$noInit = $this->getNoInitMember(); |
161
|
|
|
$class = $noInit->memberUserClass; |
162
|
|
|
$noInitUser = $class::buildNoInitModel(); |
163
|
|
|
return $this->hasMany($class, [$this->guidAttribute => $noInitUser->guidAttribute])->via('members')->inverseOf('atOrganizations'); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Get member with specified user. |
168
|
|
|
* @param User|string|integer $user |
169
|
|
|
* @return Member Null if `user` is not in this organization. |
170
|
|
|
*/ |
171
|
|
|
public function getMember($user) |
172
|
|
|
{ |
173
|
|
|
if ($user instanceof $this->memberClass) { |
174
|
|
|
return $user; |
|
|
|
|
175
|
|
|
} |
176
|
|
|
return $this->getMembers()->user($user)->one(); |
|
|
|
|
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Add member to organization. |
181
|
|
|
* @param Member|User|string|integer $member |
182
|
|
|
* @see createMemberModel |
183
|
|
|
* @see createMemberModelWithUser |
184
|
|
|
* @return boolean |
185
|
|
|
*/ |
186
|
|
|
public function addMember(&$member) |
187
|
|
|
{ |
188
|
|
|
if ($this->getIsNewRecord()) { |
189
|
|
|
return false; |
190
|
|
|
} |
191
|
|
|
$model = null; |
192
|
|
|
if ($member instanceof Member) { |
193
|
|
|
$model = $this->createMemberModel($member); |
194
|
|
|
} |
195
|
|
|
if (($member instanceof User) || is_string($member) || is_int($member)) { |
196
|
|
|
$model = $this->createMemberModelWithUser($member); |
197
|
|
|
} |
198
|
|
|
$member = $model; |
199
|
|
|
return ($member instanceof Member) ? $member->save() : false; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Create member model, and set organization with this. |
204
|
|
|
* @param Member $member If this parameter is not new record, it's organization |
205
|
|
|
* will be set with this, and return it. Otherwise, it will extract `User` |
206
|
|
|
* model and create new `Member` model. |
207
|
|
|
* @see createMemberModelWithUser |
208
|
|
|
* @return Member |
209
|
|
|
*/ |
210
|
|
|
public function createMemberModel($member) |
211
|
|
|
{ |
212
|
|
|
if (!$member->getIsNewRecord()) { |
213
|
|
|
$member->setOrganization($this); |
|
|
|
|
214
|
|
|
return $member; |
215
|
|
|
} |
216
|
|
|
return $this->createMemberModelWithUser($member->memberUser); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Create member model with user, and set organization with this. |
221
|
|
|
* @param User|string|integer $user |
222
|
|
|
* @return Member |
223
|
|
|
*/ |
224
|
10 |
|
public function createMemberModelWithUser($user) |
225
|
|
|
{ |
226
|
|
|
$config = [ |
227
|
10 |
|
'memberUser' => $user, |
228
|
10 |
|
'organization' => $this, |
229
|
10 |
|
'nickname' => '', |
230
|
10 |
|
]; |
231
|
10 |
|
if ($user->profile) { |
232
|
10 |
|
$config['nickname'] = $user->profile->nickname; |
233
|
10 |
|
} |
234
|
10 |
|
return $this->createMember($config); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Remove member. |
239
|
|
|
* @param Member|User $member |
240
|
|
|
* @return boolean |
241
|
|
|
*/ |
242
|
|
|
public function removeMember(&$member) |
243
|
|
|
{ |
244
|
|
|
if ($this->getIsNewRecord()) { |
245
|
|
|
return false; |
246
|
|
|
} |
247
|
|
|
$member = $this->getMember($member); |
|
|
|
|
248
|
|
|
return $member && $member->delete() > 0; |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
|
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.