1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.writesdown.com/ |
4
|
|
|
* @copyright Copyright (c) 2015 WritesDown |
5
|
|
|
* @license http://www.writesdown.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace backend\controllers; |
9
|
|
|
|
10
|
|
|
use common\components\Json; |
11
|
|
|
use common\models\Module; |
12
|
|
|
use common\models\search\Module as ModuleSearch; |
13
|
|
|
use Yii; |
14
|
|
|
use yii\filters\AccessControl; |
15
|
|
|
use yii\filters\VerbFilter; |
16
|
|
|
use yii\helpers\ArrayHelper; |
17
|
|
|
use yii\helpers\FileHelper; |
18
|
|
|
use yii\web\Controller; |
19
|
|
|
use yii\web\NotFoundHttpException; |
20
|
|
|
use yii\web\UploadedFile; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Class ModuleController, controlling the actions for Module model. |
24
|
|
|
* |
25
|
|
|
* @author Agiel K. Saputra <[email protected]> |
26
|
|
|
* @since 0.2.0 |
27
|
|
|
*/ |
28
|
|
|
class ModuleController extends Controller |
29
|
|
|
{ |
30
|
|
|
private $_dir; |
31
|
|
|
private $_tmp; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @inheritdoc |
35
|
|
|
*/ |
36
|
|
View Code Duplication |
public function behaviors() |
|
|
|
|
37
|
|
|
{ |
38
|
|
|
return [ |
39
|
|
|
'access' => [ |
40
|
|
|
'class' => AccessControl::className(), |
41
|
|
|
'rules' => [ |
42
|
|
|
[ |
43
|
|
|
'actions' => ['index', 'create', 'update', 'view', 'delete', 'bulk-action'], |
44
|
|
|
'allow' => true, |
45
|
|
|
'roles' => ['administrator'], |
46
|
|
|
], |
47
|
|
|
], |
48
|
|
|
], |
49
|
|
|
'verbs' => [ |
50
|
|
|
'class' => VerbFilter::className(), |
51
|
|
|
'actions' => [ |
52
|
|
|
'delete' => ['POST'], |
53
|
|
|
], |
54
|
|
|
], |
55
|
|
|
]; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Lists all Module models. |
60
|
|
|
* |
61
|
|
|
* @return mixed |
62
|
|
|
*/ |
63
|
|
View Code Duplication |
public function actionIndex() |
|
|
|
|
64
|
|
|
{ |
65
|
|
|
$searchModel = new ModuleSearch(); |
66
|
|
|
$dataProvider = $searchModel->search(Yii::$app->request->queryParams); |
67
|
|
|
|
68
|
|
|
return $this->render('index', [ |
69
|
|
|
'searchModel' => $searchModel, |
70
|
|
|
'dataProvider' => $dataProvider, |
71
|
|
|
]); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Creates a new Module model. |
76
|
|
|
* Module zip uploaded to temporary directory and extracted there. |
77
|
|
|
* Check the module directory and move the first directory of the extracted module. |
78
|
|
|
* If the module configuration is valid, save the module, if not remove the module. |
79
|
|
|
* If creation is successful, the browser will be redirected to the 'index' page. |
80
|
|
|
* |
81
|
|
|
* @return mixed |
82
|
|
|
*/ |
83
|
|
|
public function actionCreate() |
84
|
|
|
{ |
85
|
|
|
$errors = []; |
86
|
|
|
$model = new Module(['scenario' => 'create']); |
87
|
|
|
|
88
|
|
|
if (!is_dir($this->_dir)) { |
89
|
|
|
FileHelper::createDirectory($this->_dir, 0755); |
|
|
|
|
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
if (!is_dir($this->_tmp)) { |
93
|
|
|
FileHelper::createDirectory($this->_tmp, 0755); |
|
|
|
|
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
if (($model->file = UploadedFile::getInstance($model, 'file')) && $model->validate(['file'])) { |
97
|
|
|
$tmpPath = $this->_tmp . $model->file->name; |
98
|
|
|
|
99
|
|
View Code Duplication |
if (!$model->file->saveAs($tmpPath)) { |
|
|
|
|
100
|
|
|
return $this->render('create', [ |
101
|
|
|
'model' => $model, |
102
|
|
|
'error' => [Yii::t('writesdown', 'Failed to move uploaded file.')], |
103
|
|
|
]); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
$zipArchive = new \ZipArchive(); |
107
|
|
|
$zipArchive->open($tmpPath); |
108
|
|
|
|
109
|
|
View Code Duplication |
if (!$zipArchive->extractTo($this->_tmp)) { |
|
|
|
|
110
|
|
|
$zipArchive->close(); |
111
|
|
|
FileHelper::removeDirectory($this->_tmp); |
|
|
|
|
112
|
|
|
|
113
|
|
|
return $this->render('create', [ |
114
|
|
|
'model' => $model, |
115
|
|
|
'error' => [Yii::t('writesdown', 'Failed to extract file.')], |
116
|
|
|
]); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
$baseDir = substr($zipArchive->getNameIndex(0), 0, strpos($zipArchive->getNameIndex(0), '/')); |
120
|
|
|
$zipArchive->close(); |
121
|
|
|
unlink($tmpPath); |
122
|
|
|
$configPath = $this->_tmp . $baseDir . '/config/main.php'; |
123
|
|
|
|
124
|
|
View Code Duplication |
if (!is_file($configPath)) { |
|
|
|
|
125
|
|
|
FileHelper::removeDirectory($this->_tmp); |
|
|
|
|
126
|
|
|
|
127
|
|
|
return $this->render('create', [ |
128
|
|
|
'model' => $model, |
129
|
|
|
'error' => [Yii::t('writesdown', 'File configuration does not exist.')], |
130
|
|
|
]); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$config = require($configPath); |
134
|
|
|
$model->setAttributes($config); |
135
|
|
|
$model->setAttributes(['directory' => $baseDir, 'status' => Module::STATUS_NOT_ACTIVE]); |
136
|
|
|
|
137
|
|
|
if ($model->validate(['directory'])) { |
138
|
|
|
rename($this->_tmp . $baseDir, $this->_dir . $baseDir); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
FileHelper::removeDirectory($this->_tmp); |
|
|
|
|
142
|
|
|
$frontendClass = ArrayHelper::getValue($model->config, 'frontend.class', false); |
|
|
|
|
143
|
|
|
$backendClass = ArrayHelper::getValue($model->config, 'backend.class', false); |
|
|
|
|
144
|
|
|
|
145
|
|
|
if (!($frontendClass || $backendClass)) { |
146
|
|
|
$errors[] = Yii::t('writesdown', 'Invalid config.'); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
if ($backendClass && !class_exists($backendClass)) { |
150
|
|
|
$errors[] = Yii::t('writesdown', 'Invalid backend config.'); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
if ($frontendClass && !class_exists($frontendClass)) { |
154
|
|
|
$errors[] = Yii::t('writesdown', 'Invalid frontend config.'); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
$model->config = Json::encode($model->config); |
158
|
|
|
|
159
|
|
|
if (!$errors && $model->validate(['name', 'title', 'config', 'directory']) && $model->save(false)) { |
|
|
|
|
160
|
|
|
Yii::$app->getSession()->setFlash('success', Yii::t('writesdown', 'Module successfully installed')); |
|
|
|
|
161
|
|
|
|
162
|
|
|
return $this->redirect(['index']); |
163
|
|
View Code Duplication |
} else { |
|
|
|
|
164
|
|
|
if (!$model->hasErrors('directory')) { |
165
|
|
|
FileHelper::removeDirectory($this->_dir . $baseDir); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$errors = ArrayHelper::merge($errors, $model->getFirstErrors()); |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
return $this->render('create', [ |
173
|
|
|
'model' => $model, |
174
|
|
|
'error' => $errors, |
175
|
|
|
]); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Updates an existing Module model. |
180
|
|
|
* If update is successful, the browser will be redirected to the 'view' page. |
181
|
|
|
* |
182
|
|
|
* @param integer $id |
183
|
|
|
* @return mixed |
184
|
|
|
*/ |
185
|
|
|
public function actionUpdate($id) |
186
|
|
|
{ |
187
|
|
|
$model = $this->findModel($id); |
188
|
|
|
|
189
|
|
|
if ($model->load(Yii::$app->request->post())) { |
|
|
|
|
190
|
|
|
$model->config = Json::encode($model->config); |
191
|
|
|
if ($model->save()) { |
|
|
|
|
192
|
|
|
return $this->redirect(['index']); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return $this->render('update', [ |
197
|
|
|
'model' => $model, |
198
|
|
|
]); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Displays a single Module model. |
203
|
|
|
* |
204
|
|
|
* @param integer $id |
205
|
|
|
* @return mixed |
206
|
|
|
*/ |
207
|
|
|
public function actionView($id) |
208
|
|
|
{ |
209
|
|
|
return $this->render('view', [ |
210
|
|
|
'model' => $this->findModel($id), |
211
|
|
|
]); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Deletes an existing Module model. |
216
|
|
|
* If deletion is successful, the browser will be redirected to the 'index' page. |
217
|
|
|
* |
218
|
|
|
* @param integer $id |
219
|
|
|
* @return mixed |
220
|
|
|
*/ |
221
|
|
|
public function actionDelete($id) |
222
|
|
|
{ |
223
|
|
|
$model = $this->findModel($id); |
224
|
|
|
$path = Yii::getAlias($this->_dir . $model->directory); |
225
|
|
|
|
226
|
|
|
// Delete module and its directory |
227
|
|
|
if ($model->delete()) { |
|
|
|
|
228
|
|
|
FileHelper::removeDirectory($path); |
|
|
|
|
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
return $this->redirect(['index']); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Bulk action for Module triggered when button 'Apply' clicked. |
236
|
|
|
* The action depends on the value of the dropdown next to the button. |
237
|
|
|
* Only accept POST HTTP method. |
238
|
|
|
*/ |
239
|
|
|
public function actionBulkAction() |
240
|
|
|
{ |
241
|
|
|
if (Yii::$app->request->post('action') === 'active') { |
242
|
|
|
foreach (Yii::$app->request->post('ids', []) as $id) { |
243
|
|
|
$this->findModel($id)->updateAttributes(['status' => Module::STATUS_ACTIVE]); |
|
|
|
|
244
|
|
|
} |
245
|
|
|
} elseif (Yii::$app->request->post('action') === 'not-active') { |
246
|
|
|
foreach (Yii::$app->request->post('ids', []) as $id) { |
247
|
|
|
$this->findModel($id)->updateAttributes(['status' => Module::STATUS_NOT_ACTIVE]); |
|
|
|
|
248
|
|
|
} |
249
|
|
|
} elseif (Yii::$app->request->post('action') === 'deleted') { |
250
|
|
|
foreach (Yii::$app->request->post('ids', []) as $id) { |
251
|
|
|
$model = $this->findModel($id); |
252
|
|
|
$path = Yii::getAlias($this->_dir . $model->directory); |
253
|
|
|
if ($model->delete()) { |
|
|
|
|
254
|
|
|
FileHelper::removeDirectory($path); |
|
|
|
|
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* @inheritdoc |
262
|
|
|
*/ |
263
|
|
|
public function beforeAction($action) |
264
|
|
|
{ |
265
|
|
View Code Duplication |
if (parent::beforeAction($action)) { |
|
|
|
|
266
|
|
|
$this->_dir = Yii::getAlias('@modules/'); |
267
|
|
|
$this->_tmp = Yii::getAlias('@common/tmp/modules/'); |
268
|
|
|
|
269
|
|
|
return true; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
return false; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Finds the Module model based on its primary key value. |
277
|
|
|
* If the model is not found, a 404 HTTP exception will be thrown. |
278
|
|
|
* |
279
|
|
|
* @param integer $id |
280
|
|
|
* @return Module the loaded model |
281
|
|
|
* @throws NotFoundHttpException if the model cannot be found |
282
|
|
|
*/ |
283
|
|
|
protected function findModel($id) |
284
|
|
|
{ |
285
|
|
|
if (($model = Module::findOne($id)) !== null) { |
286
|
|
|
return $model; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
throw new NotFoundHttpException(Yii::t('writesdown', 'The requested page does not exist.')); |
290
|
|
|
} |
291
|
|
|
} |
292
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.