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\OrganizationQuery; |
20
|
|
|
use Yii; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Organization. |
24
|
|
|
* The organization can open sub-organizations & departments. |
25
|
|
|
* An organization can exist either alone or as a sub-organization of an |
26
|
|
|
* organization but not department. |
27
|
|
|
* |
28
|
|
|
* @method Member createMember(array $config) Create member who belongs 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
|
|
|
abstract class BaseOrganization 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
|
1 |
|
|
93
|
|
|
public function init() |
94
|
1 |
|
{ |
95
|
1 |
|
if (!is_string($this->queryClass)) { |
96
|
|
|
$this->queryClass = OrganizationQuery::class; |
97
|
1 |
|
} |
98
|
1 |
|
if (class_exists($this->memberClass)) { |
99
|
|
|
$this->addSubsidiaryClass('Member', ['class' => Member::class]); |
100
|
1 |
|
} |
101
|
1 |
|
if ($this->skipInit) { |
102
|
|
|
return; |
103
|
1 |
|
} |
104
|
1 |
|
parent::init(); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @inheritdoc |
109
|
|
|
*/ |
110
|
|
|
public function attributeLabels() |
111
|
|
|
{ |
112
|
|
|
return [ |
113
|
|
|
'guid' => Yii::t('app', 'GUID'), |
114
|
|
|
'id' => Yii::t('app', 'ID'), |
115
|
|
|
'ip' => Yii::t('app', 'IP'), |
116
|
|
|
'ip_type' => Yii::t('app', 'IP Address Type'), |
117
|
|
|
'parent' => Yii::t('app', 'Parent'), |
118
|
|
|
'created_at' => Yii::t('app', 'Create Time'), |
119
|
|
|
'updated_at' => Yii::t('app', 'Update Time'), |
120
|
|
|
'status' => Yii::t('app', 'Status'), |
121
|
|
|
'type' => Yii::t('app', 'Type'), |
122
|
|
|
]; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @inheritdoc |
127
|
1 |
|
*/ |
128
|
|
|
public static function tableName() |
129
|
1 |
|
{ |
130
|
|
|
return '{{%organization}}'; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
abstract protected function typeAttributeBehavior(); |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @inheritdoc |
137
|
1 |
|
*/ |
138
|
|
|
public function behaviors() |
139
|
1 |
|
{ |
140
|
|
|
return array_merge(parent::behaviors(), $this->typeAttributeBehavior()); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
abstract protected function getTypeRules(); |
144
|
1 |
|
|
145
|
|
|
public function rules() |
146
|
1 |
|
{ |
147
|
|
|
return array_merge(parent::rules(), $this->getTypeRules(), $this->getSelfBlameableRules()); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Get Member Query. |
152
|
|
|
* @return MemberQuery |
153
|
|
|
*/ |
154
|
|
|
public function getMembers() |
155
|
|
|
{ |
156
|
|
|
return $this->hasMany($this->memberClass, [$this->guidAttribute => $this->getNoInitMember()->createdByAttribute])->inverseOf('organization'); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Get member users' query. |
161
|
|
|
* @return BaseUserQuery |
162
|
|
|
*/ |
163
|
|
|
public function getMemberUsers() |
164
|
|
|
{ |
165
|
|
|
$noInit = $this->getNoInitMember(); |
166
|
|
|
$class = $noInit->memberUserClass; |
167
|
|
|
$noInitUser = $class::buildNoInitModel(); |
168
|
|
|
return $this->hasMany($class, [$this->guidAttribute => $noInitUser->guidAttribute])->via('members')->inverseOf('atOrganizations'); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Get member with specified user. |
173
|
|
|
* @param User|string|integer $user |
174
|
|
|
* @return Member Null if `user` is not in this organization. |
175
|
|
|
*/ |
176
|
|
|
public function getMember($user) |
177
|
|
|
{ |
178
|
|
|
if ($user instanceof $this->memberClass) { |
179
|
|
|
return $user; |
|
|
|
|
180
|
|
|
} |
181
|
|
|
return $this->getMembers()->user($user)->one(); |
|
|
|
|
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* Add member to organization. |
186
|
|
|
* @param Member|User|string|integer $member |
187
|
|
|
* @see createMemberModel |
188
|
|
|
* @see createMemberModelWithUser |
189
|
|
|
* @return boolean |
190
|
|
|
*/ |
191
|
|
|
public function addMember(&$member) |
192
|
|
|
{ |
193
|
|
|
if ($this->getIsNewRecord()) { |
194
|
|
|
return false; |
195
|
|
|
} |
196
|
|
|
$model = null; |
197
|
|
|
if ($member instanceof Member) { |
198
|
|
|
$model = $this->createMemberModel($member); |
199
|
|
|
} |
200
|
|
|
if (($member instanceof User) || is_string($member) || is_int($member)) { |
201
|
|
|
$model = $this->createMemberModelWithUser($member); |
202
|
|
|
} |
203
|
|
|
$member = $model; |
204
|
|
|
return ($member instanceof Member) ? $member->save() : false; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Create member model, and set organization with this. |
209
|
|
|
* @param Member $member If this parameter is not new record, it's organization |
210
|
|
|
* will be set with this, and return it. Otherwise, it will extract `User` |
211
|
|
|
* model and create new `Member` model. |
212
|
|
|
* @see createMemberModelWithUser |
213
|
|
|
* @return Member |
214
|
|
|
*/ |
215
|
|
|
public function createMemberModel($member) |
216
|
|
|
{ |
217
|
|
|
if (!$member->getIsNewRecord()) { |
218
|
|
|
$member->setOrganization($this); |
219
|
|
|
return $member; |
220
|
|
|
} |
221
|
|
|
return $this->createMemberModelWithUser($member->memberUser); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Create member model with user, and set organization with this. |
226
|
|
|
* @param User|string|integer $user |
227
|
|
|
* @return Member |
228
|
|
|
*/ |
229
|
|
|
public function createMemberModelWithUser($user) |
230
|
|
|
{ |
231
|
|
|
$config = [ |
232
|
|
|
'memberUser' => $user, |
233
|
|
|
'organization' => $this, |
234
|
|
|
'nickname' => '', |
235
|
|
|
]; |
236
|
|
|
if ($user->profile) { |
237
|
|
|
$config['nickname'] = $user->profile->nickname; |
238
|
|
|
} |
239
|
|
|
return $this->createMember($config); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Remove member. |
244
|
|
|
* @param Member|User $member |
245
|
|
|
* @return boolean |
246
|
|
|
*/ |
247
|
|
|
public function removeMember(&$member) |
248
|
|
|
{ |
249
|
|
|
if ($this->getIsNewRecord()) { |
250
|
|
|
return false; |
251
|
|
|
} |
252
|
|
|
$member = $this->getMember($member); |
|
|
|
|
253
|
|
|
return $member && $member->delete() > 0; |
254
|
|
|
} |
255
|
|
|
} |
256
|
|
|
|
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.