n_oct/plugins/rainlab/builder/formwidgets/BlueprintBuilder.php

321 lines
8.5 KiB
PHP

<?php namespace RainLab\Builder\FormWidgets;
use Str;
use RainLab\Builder\Classes\TailorBlueprintLibrary;
use RainLab\Builder\Models\ImportsModel;
use Backend\Classes\FormWidgetBase;
use ApplicationException;
/**
* BlueprintBuilder form widget
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
class BlueprintBuilder extends FormWidgetBase
{
/**
* {@inheritDoc}
*/
protected $defaultAlias = 'blueprintbuilder';
protected $designTimeProviders = [];
protected $blueprintInfoCache = [];
/**
* @var \Backend\Classes\WidgetBase selectWidget reference to the widget used for selecting a page.
*/
protected $selectFormWidget;
/**
* {@inheritDoc}
*/
public function init()
{
if (post('blueprintbuilder_flag')) {
$this->getSelectFormWidget();
}
}
/**
* {@inheritDoc}
*/
public function render()
{
$this->prepareVars();
return $this->makePartial('body');
}
/**
* Prepares the list data
*/
public function prepareVars()
{
$this->vars['model'] = $this->model;
$this->vars['items'] = $this->model->blueprints;
$this->vars['selectWidget'] = $this->getSelectFormWidget();
$this->vars['pluginCode'] = $this->getPluginCode();
$this->vars['emptyItem'] = [
'label' => __("Add Blueprint"),
'icon' => 'icon-life-ring',
'code' => 'newitemcode',
'url' => '/'
];
}
/**
* onRefreshBlueprintContainer
*/
public function onRefreshBlueprintContainer()
{
$uuid = post('blueprint_uuid');
$blueprintInfo = $this->getBlueprintInfo($uuid);
$blueprintConfig = (array) post('properties');
return [
'markup' => $this->renderBlueprintBody($blueprintInfo, $blueprintConfig),
'blueprintUuid' => $uuid
];
}
/**
* onShowSelectBlueprintForm
*/
public function onShowSelectBlueprintForm()
{
$this->prepareVars();
$selectedBlueprints = (array) post('blueprints') ?: [];
if ($selectedBlueprints) {
$model = $this->getSelectFormWidget()->getModel();
$model->blueprints = $selectedBlueprints;
}
return $this->makePartial('select_blueprint_form');
}
/**
* onSelectBlueprint
*/
public function onSelectBlueprint()
{
$widget = $this->getSelectFormWidget();
$data = $widget->getSaveData();
$uuids = (array) ($data['blueprint_uuid'] ?? []);
if (!$uuids) {
throw new ApplicationException(__("There are no blueprints to import, please select a blueprint and try again."));
}
$result = [];
$availableUuids = $this->getSelectFormWidget()->getModel()->getBlueprintUuidOptions();
foreach ($uuids as $uuid) {
$blueprintInfo = $this->getBlueprintInfo($uuid);
$blueprintConfig = $this->generateBlueprintConfiguration($blueprintInfo);
$result[] = $this->makePartial('blueprint', [
'blueprintUuid' => $uuid,
'blueprintConfig' => $blueprintConfig
]);
unset($availableUuids[$uuid]);
}
$includeRelated = (bool) ($data['include_related'] ?? false);
if ($includeRelated) {
foreach ($uuids as $uuid) {
$this->appendRelatedBlueprintsToOutput($uuid, $result, $availableUuids);
}
}
return ['@#blueprintList' => implode(PHP_EOL, $result)];
}
/**
* appendRelatedBlueprintsToOutput
*/
protected function appendRelatedBlueprintsToOutput($parentUuid, &$result, &$available)
{
$library = TailorBlueprintLibrary::instance();
$relatedUuids = $library->getRelatedBlueprintUuids($parentUuid);
foreach ($relatedUuids as $uuid) {
if (!isset($available[$uuid])) {
continue;
}
$blueprintInfo = $this->getBlueprintInfo($uuid);
$blueprintConfig = $this->generateBlueprintConfiguration($blueprintInfo);
$result[] = $this->makePartial('blueprint', [
'blueprintUuid' => $uuid,
'blueprintConfig' => $blueprintConfig
]);
unset($available[$uuid]);
// Recursion
$this->appendRelatedBlueprintsToOutput($uuid, $result, $available);
}
}
/**
* {@inheritDoc}
*/
public function loadAssets()
{
$this->addJs('js/blueprintbuilder.js', 'builder');
}
/**
* getPluginCode
*/
public function getPluginCode()
{
$pluginCode = post('plugin_code');
if (strlen($pluginCode)) {
return $pluginCode;
}
$pluginVector = $this->controller->getBuilderActivePluginVector();
return $pluginVector->pluginCodeObj->toCode();
}
/**
* getSelectFormWidget
*/
protected function getSelectFormWidget()
{
if ($this->selectFormWidget) {
return $this->selectFormWidget;
}
$config = $this->makeConfig('~/plugins/rainlab/builder/models/importsmodel/fields_select.yaml');
$config->model = $this->makeImportsModelInstance();
$config->alias = $this->alias . 'Select';
$config->arrayName = 'BlueprintBuilder';
$form = $this->makeWidget(\Backend\Widgets\Form::class, $config);
$form->bindToController();
return $this->selectFormWidget = $form;
}
/**
* makeImportsModelInstance
*/
protected function makeImportsModelInstance()
{
$model = new ImportsModel;
$model->setPluginCode($this->getPluginCode());
return $model;
}
//
// Methods for the internal use
//
/**
* getBlueprintDesignTimeProvider
*/
protected function getBlueprintDesignTimeProvider($providerClass)
{
if (array_key_exists($providerClass, $this->designTimeProviders)) {
return $this->designTimeProviders[$providerClass];
}
return $this->designTimeProviders[$providerClass] = new $providerClass($this->controller);
}
/**
* getPropertyValue
*/
protected function getPropertyValue($properties, $property)
{
if (array_key_exists($property, $properties)) {
return $properties[$property];
}
return null;
}
/**
* propertiesToInspectorSchema
*/
protected function propertiesToInspectorSchema($propertyConfiguration)
{
$result = [];
foreach ($propertyConfiguration as $property => $propertyData) {
$propertyData['property'] = $property;
$result[] = $propertyData;
}
return $result;
}
/**
* getBlueprintInfo
*/
protected function getBlueprintInfo($uuid)
{
if (array_key_exists($uuid, $this->blueprintInfoCache)) {
return $this->blueprintInfoCache[$uuid];
}
$library = TailorBlueprintLibrary::instance();
$blueprintInfo = $library->getBlueprintInfo($uuid);
if (!$blueprintInfo) {
throw new ApplicationException('The requested blueprint class information is not found.');
}
return $this->blueprintInfoCache[$uuid] = $blueprintInfo;
}
/**
* renderBlueprintBody
*/
protected function renderBlueprintBody($blueprintInfo, $blueprintConfig)
{
$blueprintClass = $blueprintInfo['blueprintClass'];
$blueprintObj = $blueprintInfo['blueprintObj'];
$provider = $this->getBlueprintDesignTimeProvider($blueprintInfo['designTimeProvider']);
// Inspect the generated output files
$importsModel = $this->makeImportsModelInstance();
$importsModel->fill(post());
$importsModel->blueprints[$blueprintObj->uuid] = $blueprintConfig;
$inspectedOutput = $importsModel->inspect($blueprintObj);
$blueprintConfig['inspectedOutput'] = $inspectedOutput;
return $provider->renderBlueprintBody($blueprintClass, $blueprintConfig, $blueprintObj);
}
/**
* generateBlueprintConfiguration
*/
protected function generateBlueprintConfiguration($blueprintInfo): array
{
$blueprintClass = $blueprintInfo['blueprintClass'];
$blueprintObj = $blueprintInfo['blueprintObj'];
$provider = $this->getBlueprintDesignTimeProvider($blueprintInfo['designTimeProvider']);
$model = $this->makeImportsModelInstance();
return $provider->getDefaultConfiguration($blueprintClass, $blueprintObj, $model);
}
}