I have an _form view for update and create. There is file input field, where only zip files are allowed. When zip is uploaded - it should be unzipped to a folder depending on a model name.
The problem is I have to upload it two times to have an effect, because first time doesn't give me unzipped folder.
This is the upload function in Model
public function upload()
{
$this->uploadedFile = UploadedFile::getInstance($this, 'filepath');
if (!empty($this->uploadedFile)) {
$slug = str_replace(' ', '-', strtolower(trim($this->name)));
$htmlPathRel = '/html/' . $slug . '/';
$htmlPathAbs = Yii::getAlias('@frontend') . '/web' . $htmlPathRel;
// delete old files before extracting
@array_map('unlink', glob($htmlPathAbs . '/*.*'));
@rmdir($htmlPathAbs);
// unpack new files
$zip = new \ZipArchive;
if ($zip->open(Yii::getAlias('@frontend') . '/web/uploads/' . $this->uploadedFile->name) === true) {
$indexHtmlContent = $zip->getFromName('index.html');
$order = new Order();
$toSearch = array_filter($order->attributes(), function($value) {
return strpos($value, 'name="billing_') !== false;
}) + array('<form');
if (!$indexHtmlContent) {
$this->addError('filepath', 'index.html not found in ' . $this->uploadedFile->name);
return false;
}
$notFound = [];
foreach ($toSearch as $string) {
if (strpos($indexHtmlContent, $string) === false) {
$notFound[] = $string;
}
}
if (!empty($notFound)) {
$this->addError('filepath', 'index.html doesn\'t contain required data: ' . implode(', ', $notFound));
return false;
}
if (!is_dir($htmlPathAbs)) {
mkdir($htmlPathAbs);
}
$zip->extractTo($htmlPathAbs);
$zip->close();
}
$this->filepath = $htmlPathRel . 'index.html';
$this->save();
if ($this->validate()) {
$this->uploadedFile->saveAs(Yii::getAlias('@frontend') . '/web/uploads/' . $this->uploadedFile->baseName . '.' . $this->uploadedFile->extension);
return true;
} else {
return false;
}
} else {
return false;
}
}
And this is controller create and update actions:
/**
* Creates a new Html model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate()
{
$model = new Html();
if (Yii::$app->request->isPost) {
if ($model->load(Yii::$app->request->post())) {
Product::updateRoutes();
$model->upload();
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('create', [
'model' => $model,
]);
}
/**
* Updates an existing Html model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param string $id
* @return mixed
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
if (Yii::$app->request->isPost) {
$filepath = $model->filepath;
if ($model->load(Yii::$app->request->post())) {
Product::updateRoutes();
if (!$model->upload()) {
$model->filepath = $filepath;
}
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('update', [
'model' => $model,
]);
}
What is wrong with my code?
PS: any code refactoring ideas are welcome! :)
You are saving the file to @frontend/web/uploads
after unzipping the file from this folder so it works only when the file is there - second time.