324 lines
8.5 KiB
PHP
324 lines
8.5 KiB
PHP
<?php namespace RainLab\Builder\Classes;
|
|
|
|
use Lang;
|
|
use File;
|
|
use Twig;
|
|
use Schema;
|
|
use RainLab\Builder\Classes\TailorBlueprintLibrary;
|
|
use ApplicationException;
|
|
use ValidationException;
|
|
use Throwable;
|
|
|
|
/**
|
|
* BlueprintGenerator is a helper class for generating controller class files and associated files.
|
|
*
|
|
* @package rainlab\builder
|
|
* @author Alexey Bobkov, Samuel Georges
|
|
*/
|
|
class BlueprintGenerator
|
|
{
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasMigrations;
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasVersionFile;
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasControllers;
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasPermissions;
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasNavigation;
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasExpandoModels;
|
|
use \RainLab\Builder\Classes\BlueprintGenerator\HasModels;
|
|
|
|
/**
|
|
* @var object sourceModel is the imports model
|
|
*/
|
|
protected $sourceModel;
|
|
|
|
/**
|
|
* @var array sourceBlueprints are blueprint objects that can be saved to disk
|
|
*/
|
|
protected $sourceBlueprints = [];
|
|
|
|
/**
|
|
* @var array templateVars are used when rendering templates
|
|
*/
|
|
protected $templateVars;
|
|
|
|
/**
|
|
* @var array filesGenerated by this process
|
|
*/
|
|
protected $filesGenerated;
|
|
|
|
/**
|
|
* @var array filesValidated by this process
|
|
*/
|
|
protected $filesValidated;
|
|
|
|
/**
|
|
* @var array blueprintFiles to decommission
|
|
*/
|
|
protected $blueprintFiles = [];
|
|
|
|
/**
|
|
* @var array migrationScripts that have been generated
|
|
*/
|
|
protected $migrationScripts = [];
|
|
|
|
/**
|
|
* __construct
|
|
*/
|
|
public function __construct($source)
|
|
{
|
|
$this->sourceModel = $source;
|
|
}
|
|
|
|
/**
|
|
* generate
|
|
*/
|
|
public function inspect($blueprint)
|
|
{
|
|
$this->setBlueprintContext($blueprint);
|
|
|
|
$result = [
|
|
'controllerFile' => null,
|
|
'modelFiles' => [],
|
|
'migrationFiles' => [],
|
|
'errorMessage' => null
|
|
];
|
|
|
|
try {
|
|
if ($model = $this->makeControllerModel()) {
|
|
$result['controllerFile'] = $model->getControllerFilePath();
|
|
}
|
|
|
|
if ($model = $this->makeModelModel()) {
|
|
$result['modelFiles'][] = $model->getModelFilePath();
|
|
}
|
|
|
|
foreach ($this->makeExpandoModels(true) as $model) {
|
|
$result['modelFiles'][] = $model->getModelFilePath();
|
|
}
|
|
|
|
$result['migrationFiles'] = array_keys($this->inspectMigrations());
|
|
}
|
|
catch (Throwable $ex) {
|
|
$result['errorMessage'] = $ex->getMessage();
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* generate
|
|
*/
|
|
public function generate()
|
|
{
|
|
$this->templateVars = [];
|
|
$this->filesGenerated = [];
|
|
$this->filesValidated = [];
|
|
$this->blueprintFiles = [];
|
|
$this->migrationScripts = [];
|
|
$this->sourceBlueprints = [];
|
|
|
|
$this->loadSourceBlueprints();
|
|
$this->validateNavigation();
|
|
|
|
// Validate
|
|
foreach ($this->sourceBlueprints as $blueprint) {
|
|
$this->setBlueprintContext($blueprint);
|
|
$this->validateModel();
|
|
$this->validateExpandoModels();
|
|
$this->validateController();
|
|
$this->validatePermission();
|
|
}
|
|
|
|
// Generate
|
|
try {
|
|
foreach ($this->sourceBlueprints as $blueprint) {
|
|
$this->setBlueprintContext($blueprint);
|
|
$this->generateMigrations();
|
|
$this->generateModel();
|
|
$this->generateExpandoModels();
|
|
$this->generateController();
|
|
$this->generatePermission();
|
|
|
|
$this->blueprintFiles[] = $blueprint->getFilePath();
|
|
}
|
|
}
|
|
catch (Throwable $ex) {
|
|
$this->rollback();
|
|
throw $ex;
|
|
}
|
|
|
|
$this->generateNavigation();
|
|
$this->generateVersionUpdate();
|
|
|
|
if ($this->sourceModel->deleteBlueprintData) {
|
|
$this->deleteGeneratedBlueprintData();
|
|
}
|
|
|
|
if ($this->sourceModel->disableBlueprints) {
|
|
$this->disableGeneratedBlueprints();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* loadSourceBlueprints
|
|
*/
|
|
protected function loadSourceBlueprints()
|
|
{
|
|
$blueprintLib = TailorBlueprintLibrary::instance();
|
|
|
|
foreach ($this->sourceModel->blueprints as $uuid => $config) {
|
|
$blueprint = $blueprintLib->getBlueprintObject($uuid);
|
|
if ($blueprint) {
|
|
$this->sourceBlueprints[$uuid] = $blueprint;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* setBlueprintContext
|
|
*/
|
|
protected function setBlueprintContext($blueprint)
|
|
{
|
|
$config = $this->sourceModel->blueprints[$blueprint->uuid] ?? [];
|
|
|
|
$this->sourceModel->setBlueprintContext($blueprint, $config);
|
|
|
|
$this->setTemplateVars();
|
|
}
|
|
|
|
/**
|
|
* disableGeneratedBlueprints
|
|
*/
|
|
protected function disableGeneratedBlueprints()
|
|
{
|
|
foreach ($this->blueprintFiles as $filePath) {
|
|
File::move(
|
|
$filePath,
|
|
str_replace('.yaml', '.yaml.bak', $filePath)
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* deleteGeneratedBlueprintData
|
|
*/
|
|
protected function deleteGeneratedBlueprintData()
|
|
{
|
|
foreach ($this->sourceBlueprints as $blueprint) {
|
|
$contentTable = $blueprint->getContentTableName();
|
|
Schema::dropIfExists($contentTable);
|
|
|
|
$joinTable = $blueprint->getJoinTableName();
|
|
Schema::dropIfExists($joinTable);
|
|
|
|
$repeaterTable = $blueprint->getRepeaterTableName();
|
|
Schema::dropIfExists($repeaterTable);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* setTemplateVars
|
|
*/
|
|
protected function setTemplateVars()
|
|
{
|
|
$pluginCodeObj = $this->sourceModel->getPluginCodeObj();
|
|
|
|
$this->templateVars = $this->getConfig();
|
|
$this->templateVars['pluginNamespace'] = $pluginCodeObj->toPluginNamespace();
|
|
$this->templateVars['pluginCode'] = $pluginCodeObj->toCode();
|
|
}
|
|
|
|
/**
|
|
* getTemplatePath
|
|
*/
|
|
protected function getTemplatePath($template)
|
|
{
|
|
return __DIR__.'/blueprintgenerator/templates/'.$template;
|
|
}
|
|
|
|
/**
|
|
* parseTemplate
|
|
*/
|
|
protected function parseTemplate($templatePath, $vars = [])
|
|
{
|
|
$template = File::get($templatePath);
|
|
|
|
$vars = array_merge($this->templateVars, $vars);
|
|
$code = Twig::parse($template, $vars);
|
|
|
|
return $code;
|
|
}
|
|
|
|
/**
|
|
* writeFile
|
|
*/
|
|
protected function writeFile($path, $data)
|
|
{
|
|
$fileDirectory = dirname($path);
|
|
if (!File::isDirectory($fileDirectory)) {
|
|
if (!File::makeDirectory($fileDirectory, 0777, true, true)) {
|
|
throw new ApplicationException(Lang::get('rainlab.builder::lang.common.error_make_dir', [
|
|
'name' => $fileDirectory
|
|
]));
|
|
}
|
|
}
|
|
|
|
if (@File::put($path, $data) === false) {
|
|
throw new ApplicationException(Lang::get('rainlab.builder::lang.controller.error_save_file', [
|
|
'file' => basename($path)
|
|
]));
|
|
}
|
|
|
|
@File::chmod($path);
|
|
$this->filesGenerated[] = $path;
|
|
}
|
|
|
|
/**
|
|
* rollback
|
|
*/
|
|
protected function rollback()
|
|
{
|
|
foreach ($this->filesGenerated as $path) {
|
|
@unlink($path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* makeTabs
|
|
*/
|
|
protected function makeTabs($str)
|
|
{
|
|
return str_replace('\t', ' ', $str);
|
|
}
|
|
|
|
/**
|
|
* getConfig
|
|
*/
|
|
protected function getConfig($key = null, $default = null)
|
|
{
|
|
return $this->sourceModel->getBlueprintConfig($key, $default);
|
|
}
|
|
|
|
/**
|
|
* validateUniqueFiles
|
|
*/
|
|
protected function validateUniqueFiles(array $files)
|
|
{
|
|
if (!is_array($this->filesValidated)) {
|
|
$this->filesValidated = [];
|
|
}
|
|
|
|
foreach ($files as $path) {
|
|
if (File::isFile($path) || in_array($path, $this->filesValidated)) {
|
|
throw new ValidationException([
|
|
'modelClass' => __("File [:file] already exists when trying to import [:blueprint]", [
|
|
'file' => basename(dirname($path)) . '/' . basename($path),
|
|
'blueprint' => $this->sourceModel->getBlueprintObject()->handle ?? 'unknown'
|
|
])
|
|
]);
|
|
}
|
|
}
|
|
|
|
$this->filesValidated = array_merge($this->filesValidated, $files);
|
|
}
|
|
}
|