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\models\Option; |
11
|
|
|
use Yii; |
12
|
|
|
use yii\base\DynamicModel; |
13
|
|
|
use yii\base\Exception; |
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\UploadedFile; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* ThemeController, controlling the actions for theme. |
23
|
|
|
* |
24
|
|
|
* @author Agiel K. Saputra <[email protected]> |
25
|
|
|
* @since 0.1.0 |
26
|
|
|
*/ |
27
|
|
|
class ThemeController extends Controller |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* @var string Path to theme directory. |
31
|
|
|
*/ |
32
|
|
|
private $_dir; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var string Path to temporary directory of theme. |
36
|
|
|
*/ |
37
|
|
|
private $_tmp; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var string Path to thumbnail directory of theme. |
41
|
|
|
*/ |
42
|
|
|
private $_thumbDir; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var string Base url of theme thumbnail. |
46
|
|
|
*/ |
47
|
|
|
private $_thumbBaseUrl; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @inheritdoc |
51
|
|
|
*/ |
52
|
|
View Code Duplication |
public function behaviors() |
|
|
|
|
53
|
|
|
{ |
54
|
|
|
return [ |
55
|
|
|
'access' => [ |
56
|
|
|
'class' => AccessControl::className(), |
57
|
|
|
'rules' => [ |
58
|
|
|
[ |
59
|
|
|
'actions' => ['index', 'upload', 'detail', 'install', 'delete', 'ajax-detail'], |
60
|
|
|
'allow' => true, |
61
|
|
|
'roles' => ['administrator'], |
62
|
|
|
], |
63
|
|
|
], |
64
|
|
|
], |
65
|
|
|
'verbs' => [ |
66
|
|
|
'class' => VerbFilter::className(), |
67
|
|
|
'actions' => [ |
68
|
|
|
'install' => ['post'], |
69
|
|
|
'delete' => ['post'], |
70
|
|
|
], |
71
|
|
|
], |
72
|
|
|
]; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Scan theme directory to get list of all available themes. |
77
|
|
|
* |
78
|
|
|
* @return string |
79
|
|
|
*/ |
80
|
|
|
public function actionIndex() |
81
|
|
|
{ |
82
|
|
|
$installed = Option::get('theme'); |
83
|
|
|
$themes[] = $this->getConfig($installed); |
|
|
|
|
84
|
|
|
|
85
|
|
|
if (!is_dir($this->_dir)) { |
86
|
|
|
FileHelper::createDirectory($this->_dir, 0755); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
if (!is_dir($this->_thumbDir)) { |
90
|
|
|
FileHelper::createDirectory($this->_thumbDir, 0755); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$arrThemes = scandir($this->_dir); |
94
|
|
|
|
95
|
|
|
foreach ($arrThemes as $theme) { |
96
|
|
|
if (is_dir($this->_dir . $theme) && $theme !== '.' && $theme !== '..' && $theme !== $installed) { |
97
|
|
|
$themes[] = $this->getConfig($theme); |
98
|
|
|
} |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
return $this->render('index', [ |
102
|
|
|
'themes' => $themes, |
103
|
|
|
'installed' => $installed, |
104
|
|
|
]); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Register new theme. |
109
|
|
|
* Theme zip uploaded to temporary directory and extracted there. |
110
|
|
|
* Check the theme directory and move the first directory of the extracted theme. |
111
|
|
|
* If registration is successful, the browser will be redirected to the 'index' page. |
112
|
|
|
* |
113
|
|
|
* @return string |
114
|
|
|
*/ |
115
|
|
|
public function actionUpload() |
116
|
|
|
{ |
117
|
|
|
$errors = []; |
118
|
|
|
$model = new DynamicModel(['file']); |
119
|
|
|
$model->addRule(['file'], 'required') |
120
|
|
|
->addRule(['file'], 'file', ['extensions' => 'zip']); |
121
|
|
|
|
122
|
|
|
if (!is_dir($this->_dir)) { |
123
|
|
|
FileHelper::createDirectory($this->_dir, 0755); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
if (!is_dir($this->_tmp)) { |
127
|
|
|
FileHelper::createDirectory($this->_tmp, 0755); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
if (!is_dir($this->_thumbDir)) { |
131
|
|
|
FileHelper::createDirectory($this->_thumbDir, 0755); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
if (($model->file = UploadedFile::getInstance($model, 'file')) && $model->validate()) { |
135
|
|
|
$themeTempPath = $this->_tmp . $model->file->name; |
136
|
|
|
|
137
|
|
View Code Duplication |
if (!$model->file->saveAs($themeTempPath)) { |
|
|
|
|
138
|
|
|
return $this->render('upload', [ |
139
|
|
|
'model' => $model, |
140
|
|
|
'errors' => [Yii::t('writesdown', 'Failed to move uploaded file')], |
141
|
|
|
]); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
$zipArchive = new \ZipArchive(); |
145
|
|
|
$zipArchive->open($themeTempPath); |
146
|
|
|
|
147
|
|
View Code Duplication |
if (!$zipArchive->extractTo($this->_tmp)) { |
|
|
|
|
148
|
|
|
$zipArchive->close(); |
149
|
|
|
FileHelper::removeDirectory($this->_tmp); |
150
|
|
|
|
151
|
|
|
return $this->render('upload', [ |
152
|
|
|
'model' => $model, |
153
|
|
|
'errors' => [Yii::t('writesdown', 'Failed to extract file.')], |
154
|
|
|
]); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
$baseDir = substr($zipArchive->getNameIndex(0), 0, strpos($zipArchive->getNameIndex(0), '/')); |
158
|
|
|
$zipArchive->close(); |
159
|
|
|
|
160
|
|
|
if (is_dir($this->_dir . $baseDir)) { |
161
|
|
|
FileHelper::removeDirectory($this->_tmp); |
162
|
|
|
$errors[] = Yii::t('writesdown', 'Theme with the same directory already exist.'); |
163
|
|
|
} else { |
164
|
|
|
rename($this->_tmp . $baseDir, $this->_dir . $baseDir); |
165
|
|
|
FileHelper::removeDirectory($this->_tmp); |
166
|
|
|
|
167
|
|
|
if (is_file($this->_dir . $baseDir . '/screenshot.png')) { |
168
|
|
|
copy($this->_dir . $baseDir . '/screenshot.png', $this->_thumbDir . $baseDir . '.png'); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
foreach (ArrayHelper::getValue($this->getConfig($baseDir), 'upload', []) as $type) { |
172
|
|
|
try { |
173
|
|
|
Yii::createObject($type); |
174
|
|
|
} catch (Exception $e) { |
|
|
|
|
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
Yii::$app->getSession()->setFlash('success', Yii::t('writesdown', 'Theme successfully uploaded')); |
|
|
|
|
179
|
|
|
|
180
|
|
|
return $this->redirect(['index']); |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $this->render('upload', [ |
185
|
|
|
'model' => $model, |
186
|
|
|
'errors' => $errors, |
187
|
|
|
]); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Show theme detail based on theme dir then render theme detail view. |
192
|
|
|
* |
193
|
|
|
* @param string $theme |
194
|
|
|
* |
195
|
|
|
* @return string |
196
|
|
|
*/ |
197
|
|
|
public function actionDetail($theme) |
198
|
|
|
{ |
199
|
|
|
return $this->render('detail', [ |
200
|
|
|
'theme' => $this->getConfig($theme), |
201
|
|
|
'installed' => Option::get('theme'), |
202
|
|
|
]); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Install selected theme and run install and uninstall action based on config. |
207
|
|
|
* |
208
|
|
|
* @param string $theme |
209
|
|
|
* |
210
|
|
|
* @return \yii\web\Response |
211
|
|
|
*/ |
212
|
|
|
public function actionInstall($theme) |
213
|
|
|
{ |
214
|
|
|
foreach (ArrayHelper::getValue($this->getConfig(Option::get('theme')), 'uninstall', []) as $type) { |
215
|
|
|
try { |
216
|
|
|
Yii::createObject($type); |
217
|
|
|
} catch (Exception $e) { |
|
|
|
|
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
foreach (ArrayHelper::getValue($this->getConfig($theme), 'install', []) as $type) { |
222
|
|
|
try { |
223
|
|
|
Yii::createObject($type); |
224
|
|
|
} catch (Exception $e) { |
|
|
|
|
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
if (Option::set('theme', $theme)) { |
229
|
|
|
Yii::$app->getSession()->setFlash('success', Yii::t('writesdown', "Theme successfully installed.")); |
|
|
|
|
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
return $this->redirect(['index']); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Delete and existing theme and run action based on config. |
237
|
|
|
* |
238
|
|
|
* @param string $theme |
239
|
|
|
* |
240
|
|
|
* @return \yii\web\Response |
241
|
|
|
*/ |
242
|
|
|
public function actionDelete($theme) |
243
|
|
|
{ |
244
|
|
|
if ($theme !== Option::get('theme')) { |
245
|
|
|
|
246
|
|
|
foreach (ArrayHelper::getValue($this->getConfig($theme), 'delete', []) as $type) { |
247
|
|
|
try { |
248
|
|
|
Yii::createObject($type); |
249
|
|
|
} catch (Exception $e) { |
|
|
|
|
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
FileHelper::removeDirectory($this->_dir . $theme); |
254
|
|
|
|
255
|
|
|
if (is_file($this->_thumbDir . $theme . '.png')) { |
256
|
|
|
unlink($this->_thumbDir . $theme . '.png'); |
257
|
|
|
} |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
return $this->redirect(['index']); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* Detail selected theme via AJAX then show it on modal. |
265
|
|
|
* |
266
|
|
|
* @param string $theme |
267
|
|
|
* |
268
|
|
|
* @return string |
269
|
|
|
*/ |
270
|
|
|
public function actionAjaxDetail($theme) |
271
|
|
|
{ |
272
|
|
|
return $this->renderPartial('_theme-detail', [ |
273
|
|
|
'theme' => $this->getConfig($theme), |
274
|
|
|
'installed' => Option::get('theme'), |
275
|
|
|
]); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* @inheritdoc |
280
|
|
|
*/ |
281
|
|
|
public function beforeAction($action) |
282
|
|
|
{ |
283
|
|
|
if (parent::beforeAction($action)) { |
284
|
|
|
$this->_dir = Yii::getAlias('@themes/'); |
|
|
|
|
285
|
|
|
$this->_tmp = Yii::getAlias('@common/tmp/themes/'); |
|
|
|
|
286
|
|
|
$this->_thumbDir = Yii::getAlias('@webroot/themes/'); |
|
|
|
|
287
|
|
|
$this->_thumbBaseUrl = Yii::getAlias('@web/themes/'); |
|
|
|
|
288
|
|
|
|
289
|
|
|
return true; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
return false; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Get theme config based on theme directory; |
297
|
|
|
* |
298
|
|
|
* @param $theme |
299
|
|
|
* @return array|mixed |
300
|
|
|
*/ |
301
|
|
|
protected function getConfig($theme) |
302
|
|
|
{ |
303
|
|
|
$config = []; |
304
|
|
|
$configPath = $this->_dir . $theme . '/config/main.php'; |
305
|
|
|
|
306
|
|
|
if (is_file($configPath)) { |
307
|
|
|
$config = require($configPath); |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
$config['thumbnail'] = is_file($this->_thumbDir . $theme . '.png') |
311
|
|
|
? $this->_thumbBaseUrl . $theme . '.png' |
312
|
|
|
: Yii::getAlias('@web/img/themes.png'); |
313
|
|
|
$config['directory'] = $theme; |
314
|
|
|
|
315
|
|
|
if (!isset($config['info']['Name'])) { |
316
|
|
|
$config['info']['Name'] = $theme; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
return $config; |
320
|
|
|
} |
321
|
|
|
} |
322
|
|
|
|
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.