Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export and import widget templates #49

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
67 changes: 65 additions & 2 deletions src/controllers/crud/WidgetTemplateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
namespace hrzg\widget\controllers\crud;

use hrzg\widget\assets\WidgetAsset;
use hrzg\widget\models\crud\WidgetTemplate;
use yii\helpers\Url;
use hrzg\widget\exceptions\WidgetTemplateCreateException;
use hrzg\widget\helpers\WidgetTemplateExport;
use hrzg\widget\models\WidgetTemplateImport;
use yii\web\HttpException;
use yii\web\Response;
use yii\web\UploadedFile;

/**
* Class WidgetTemplateController
*
* @package hrzg\widget\controllers\crud
* @author Christopher Stebe <[email protected]>
*/
Expand All @@ -18,4 +23,62 @@ public function beforeAction($action)
WidgetAsset::register($this->view);
return parent::beforeAction($action);
}

/**
* Export given widget template
*
* @param string $id
* @return void
* @throws \yii\base\ErrorException
* @throws \yii\base\ExitException
* @throws \yii\web\HttpException
*/
public function actionExport($id)
{
$model = $this->findModel($id);

$export = new WidgetTemplateExport([
'widgetTemplate' => $model
]);

if ($export->generateTar() === false) {
throw new HttpException(500, \Yii::t('widgets', 'Error while exporting widget template'));
}

if (\Yii::$app->getResponse()->sendFile($export->getTarFilePath()) instanceof Response) {
unlink($export->getTarFilePath());
if (!$export->cleanupTmpDirectory()) {
\Yii::$app->getSession()->addFlash('info', \Yii::t('widgets', 'Error while creating temporary export directory'));
}
} else {
throw new HttpException(500, \Yii::t('widgets', 'Error while downloading widget template'));
}
\Yii::$app->end();
}

public function actionImport()
{

$model = new WidgetTemplateImport();
if (\Yii::$app->request->isPost) {
$model->tarFiles = UploadedFile::getInstances($model, 'tarFiles');
if ($model->uploadAndImport()) {
if (!$model->getTmpDirectoryWasRemoved()) {
\Yii::$app->getSession()->addFlash('info', \Yii::t('widgets', 'Error while creating temporary import directory'));
}
\Yii::$app->getSession()->addFlash('success', \Yii::t('widgets', 'Import was successful'));
return $this->refresh();
}
}

$this->view->title = \Yii::t('widgets','Import');
$this->view->params['breadcrumbs'][]= [
'label' => \Yii::t('widgets','Widget Templates'),
'url' => ['index']
];
$this->view->params['breadcrumbs'][]= $this->view->title;
return $this->render('import', [
'model' => $model
]);
}
}
172 changes: 172 additions & 0 deletions src/helpers/WidgetTemplateExport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<?php

namespace hrzg\widget\helpers;

use hrzg\widget\models\crud\base\WidgetTemplate;
use yii\base\BaseObject;
use yii\base\InvalidConfigException;
use yii\helpers\FileHelper;
use yii\helpers\Inflector;
use yii\helpers\Json;

/**
* --- PUBLIC PROPERTIES ---
*
* @property-write WidgetTemplate $widgetTemplate
* @property string $tarFileName
*
* --- MAGIC GETTERS ---
*
* @property-read string $tarFilePath
*
* @author Elias Luhr
*/
class WidgetTemplateExport extends BaseObject
{
public const META_FILE = 'meta.json';
public const TEMPLATE_FILE = 'template.twig';
public const SCHEMA_FILE = 'schema.json';


/**
* Export extract directory of the generated tar file
* If this is set with an alias, it will be automatically resolved later on
*
* @var string
*/
protected $baseExportDirectory = '@runtime/tmp/widgets/export';
/**
* Will be set to a tmp directory with a bit of randomness to prevent race conditions
*
* @var string
*/
protected $_exportDirectory;

/**
* Optional name for the tar file. If not set, the value of the $name attribute from the widget template is used.
* The name must contain the file extension
*
* @var string
*/
public $tarFileName;

/**
* Instance of the to be exported widget template instance
*
* @var WidgetTemplate
*/
protected $_widgetTemplate;

/**
* @return WidgetTemplate
*/
protected function getWidgetTemplate(): WidgetTemplate
{
return $this->_widgetTemplate;
}

/**
* @param WidgetTemplate $widgetTemplate
*/
public function setWidgetTemplate(WidgetTemplate $widgetTemplate): void
{
$this->_widgetTemplate = $widgetTemplate;
}

/**
* @return void
* @throws \yii\base\Exception if the export directory could not be created due to an php error
* @throws \yii\base\InvalidConfigException if either the export directory is not set or the export directory cannot
* be created due to permission errors or the widget template is configured incorrectly
*/
public function init()
{
parent::init();

// Check if instance of widget template is not a new record or a new instance
if ($this->widgetTemplate instanceof WidgetTemplate && $this->widgetTemplate->getIsNewRecord() === true) {
throw new InvalidConfigException('Widget template must be saved at least once');
}

// Set tar name to widget template name if not set
if (empty($this->tarFileName)) {
$this->tarFileName = Inflector::slug($this->getWidgetTemplate()->name) . '.tar';
}

$this->_exportDirectory = \Yii::getAlias($this->baseExportDirectory . DIRECTORY_SEPARATOR . uniqid('widget-template-export', false));
}

/**
* Absolute file path to the tar file
*
* @return string
*/
public function getTarFilePath(): string
{
return $this->_exportDirectory . DIRECTORY_SEPARATOR . $this->tarFileName;
}

/**
* Generate a tar file with the following contents
* - template file (twig): the content from the twig_template attribute of the given widget template
* - schema file (json): the content from the twig_template attribute of the given widget template
* - meta file (json): this contains some information about the export
*
* @return bool
* @throws \yii\base\Exception
* @throws \yii\base\InvalidConfigException
*/
public function generateTar(): bool
{

// Create export directory if not exists
if (FileHelper::createDirectory($this->_exportDirectory) === false) {
throw new InvalidConfigException("Error while creating directory at: $this->_exportDirectory");
}

// Remove existing tar file
if (is_file($this->getTarFilePath()) && unlink($this->getTarFilePath()) === false) {
return false;
}

// Create the tar archive
$phar = new \PharData($this->getTarFilePath());
// Add files by string
$phar->addFromString(self::TEMPLATE_FILE, $this->getWidgetTemplate()->twig_template);
$phar->addFromString(self::SCHEMA_FILE, $this->getWidgetTemplate()->json_schema);
$phar->addFromString(self::META_FILE, $this->metaFileContent());

return true;
}


/**
* @return bool
* @throws \yii\base\ErrorException
*/
public function cleanupTmpDirectory(): bool
{
FileHelper::removeDirectory($this->_exportDirectory);
return !is_dir($this->_exportDirectory);
}

/**
* Generate json file content based on the value of the widget template $json_schema property
*
* @return string
*/
protected function metaFileContent(): string
{
$data = [
'id' => $this->getWidgetTemplate()->id,
'name' => $this->getWidgetTemplate()->name,
'php_class' => $this->getWidgetTemplate()->php_class,
'created_at' => $this->getWidgetTemplate()->created_at,
'updated_at' => $this->getWidgetTemplate()->updated_at,
'exported_at' => date('Y-m-d H:i:s'),
'download_url' => \Yii::$app->getRequest()->getAbsoluteUrl()
];
return Json::encode($data);
}

}
Loading