release
This commit is contained in:
parent
75a8dcaa3b
commit
3342a9ee4b
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "drobnitsa/dictionary-yii2-generator",
|
||||
"name": "drobnitsa/yii2-gii-dictionary-generator",
|
||||
"description": "Генератор справочников для проектов",
|
||||
"type": "yii2-extension",
|
||||
"authors": [
|
||||
@ -13,7 +13,7 @@
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"drobnitsa\\DictionaryYii2Generator\\": "src/"
|
||||
"drobnitsa\\dictionaryGenerator\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,26 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace Drobnitsa\DictionaryYii2Generator;
|
||||
namespace drobnitsa\dictionaryGenerator;
|
||||
|
||||
class Generator
|
||||
use common\models\Addition;
|
||||
use Yii;
|
||||
use yii\gii\CodeFile;
|
||||
use yii\helpers\Inflector;
|
||||
|
||||
class Generator extends yii\gii\Generator
|
||||
{
|
||||
public function generate($params = [])
|
||||
public $modelNs = 'common\models';
|
||||
public $modelName = '';
|
||||
public $attributes;
|
||||
public $moduleId = 'backend';
|
||||
public $controllerId = '';
|
||||
public $generateMigration = true;
|
||||
public $migrationNs = 'console\migrations';
|
||||
public $migrationName = '';
|
||||
|
||||
public function getName()
|
||||
{
|
||||
$namespace = $params['namespace'] ?? 'app\\controllers';
|
||||
$basePath = $params['basePath'] ?? \Yii::getAlias('@app');
|
||||
|
||||
// пример генерации файла
|
||||
$filePath = $basePath . '/controllers/' . ucfirst($params['name']) . 'Controller.php';
|
||||
|
||||
$content = "<?php\n\nnamespace {$namespace};\n\nclass " . ucfirst($params['name']) . "Controller extends \\yii\\web\\Controller\n{\n // ...\n}\n";
|
||||
|
||||
// создаем файл
|
||||
if (!file_exists(dirname($filePath))) {
|
||||
mkdir(dirname($filePath), 0777, true);
|
||||
return 'Dictionary CRUD Generator';
|
||||
}
|
||||
|
||||
file_put_contents($filePath, $content);
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Генерирует контроллер и виды для заданной модели и полей.';
|
||||
}
|
||||
|
||||
return $filePath;
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['modelNs', 'modelName', 'moduleId', 'controllerId'], 'required'],
|
||||
[['migrationNs', 'modelNs', 'moduleId'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'],
|
||||
['modelName', 'validateModelClass'],
|
||||
['generateMigration', 'boolean'],
|
||||
[['migrationName', 'controllerId'], 'string'],
|
||||
['attributes', 'safe']
|
||||
// ['attributes', 'string', 'length' => [0, 1024]],
|
||||
];
|
||||
}
|
||||
|
||||
public function validateModelClass($attribute, $params)
|
||||
{
|
||||
if (!class_exists($this->modelClass)) {
|
||||
$this->addError($attribute, 'Модель не найдена.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getModelClass()
|
||||
{
|
||||
return $this->modelNs . '\\' . $this->modelName;
|
||||
}
|
||||
|
||||
public function getControllerNs()
|
||||
{
|
||||
return $this->moduleId . '\controllers';
|
||||
}
|
||||
|
||||
public function generate()
|
||||
{
|
||||
$controllerName = Inflector::id2camel($this->controllerId).'Controller';
|
||||
|
||||
|
||||
$params = [
|
||||
'modelName' => $this->modelName,
|
||||
'modelClass' => $this->modelClass,
|
||||
'controllerNs' => $this->controllerNs,
|
||||
'controllerId' => $this->controllerId,
|
||||
'controllerName' => Inflector::id2camel($this->controllerId),
|
||||
'attributes' => $this->attributes,
|
||||
'migrationName' => $this->migrationName,
|
||||
'moduleId' => $this->moduleId
|
||||
];
|
||||
|
||||
$controllerCode = $this->render('controller.php', $params);
|
||||
$viewCode = $this->render('view.php', $params);
|
||||
$searchCode = $this->render('_search.php', $params);
|
||||
|
||||
$nsPath = str_replace('\\', '/', $this->controllerNs);
|
||||
|
||||
$controllerPath = \Yii::getAlias("@$nsPath/{$controllerName}.php");
|
||||
$viewDir = \Yii::getAlias("@backend/views/{$this->controllerId}");
|
||||
|
||||
$files = [
|
||||
new CodeFile($controllerPath, $controllerCode),
|
||||
new CodeFile("$viewDir/index.php", $viewCode),
|
||||
new CodeFile("$viewDir/_search.php", $searchCode),
|
||||
];
|
||||
|
||||
if($this->generateMigration && $this->migrationName) {
|
||||
$nsPath = str_replace('\\', '/', $this->migrationNs);
|
||||
$migrationPath = \Yii::getAlias("@$nsPath/{$this->migrationName}.php");
|
||||
$migrationCode = $this->render('migration.php', $params);
|
||||
$files[] = new CodeFile($migrationPath, $migrationCode);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает список атрибутов модели для выбора в форме
|
||||
*/
|
||||
public function getModelAttributes($plain = true)
|
||||
{
|
||||
if (!class_exists($this->modelClass)) {
|
||||
return [];
|
||||
}
|
||||
$model = new $this->modelClass();
|
||||
if(!$plain) {
|
||||
$result = [];
|
||||
foreach ($model->attributes() as $attribute) {
|
||||
$result[$attribute] = $attribute;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return $model->attributes();
|
||||
// return $model->attributeLabels();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), [
|
||||
'modelNs' => 'Model namespace',
|
||||
'moduleId' => 'Module',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hints()
|
||||
{
|
||||
return array_merge(parent::hints(), [
|
||||
'modelNs' => 'This is the namespace for the source model, e.g., <code>app\models</code>',
|
||||
'moduleId' => 'This is the module name for the controller and view to be generated, e.g., <code>app\controllers</code>',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function stickyAttributes()
|
||||
{
|
||||
return array_merge(
|
||||
parent::stickyAttributes(),
|
||||
[
|
||||
'modelNs',
|
||||
'moduleId',
|
||||
'migrationNs'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function actionGetAttributes()
|
||||
{
|
||||
if(class_exists($this->modelClass)) {
|
||||
return json_encode([
|
||||
'result' => true,
|
||||
'controller_id' => Inflector::pluralize(Inflector::camel2id($this->modelName)),
|
||||
'attributes' => $this->getModelAttributes()
|
||||
]);
|
||||
}
|
||||
return json_encode(['result' => false]);
|
||||
}
|
||||
}
|
||||
13
src/assets/MainAsset.php
Normal file
13
src/assets/MainAsset.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace drobnitsa\dictionaryGenerator\assets;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
class MainAsset extends AssetBundle
|
||||
{
|
||||
public $sourcePath = '@vendor/drobnitsa/yii2-gii-dictionary-generator/src/assets';
|
||||
|
||||
public $js = [
|
||||
'main.js',
|
||||
];
|
||||
}
|
||||
99
src/assets/main.js
Normal file
99
src/assets/main.js
Normal file
@ -0,0 +1,99 @@
|
||||
(function() {
|
||||
|
||||
const checkbox = document.querySelector('form #generator-generatemigration');
|
||||
|
||||
function toggleFields() {
|
||||
const isChecked = checkbox.checked;
|
||||
const migrationFields = document.querySelectorAll('form .field-generator-migrationns, form .field-generator-migrationname');
|
||||
migrationFields.forEach(function(item) {
|
||||
item.style.display = isChecked ? '' : 'none';
|
||||
});
|
||||
}
|
||||
checkbox.addEventListener('change', toggleFields);
|
||||
|
||||
toggleFields();
|
||||
|
||||
let modelNsInput = document.querySelector('#generator-modelns');
|
||||
let modelInput = document.querySelector('#generator-modelname');
|
||||
let controllerInput = document.querySelector('#generator-controllerid');
|
||||
let attributesContainer = document.querySelector('#generator-attributes');
|
||||
|
||||
let autoUpdateController = true;
|
||||
let debounceTimer = null;
|
||||
|
||||
controllerInput && controllerInput.addEventListener('input', () => {
|
||||
autoUpdateController = false;
|
||||
});
|
||||
|
||||
modelInput && modelInput.addEventListener('input', () => {
|
||||
if (debounceTimer) clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(() => {
|
||||
const modelNs = modelNsInput.value.trim();
|
||||
if (modelNs.length === 0) return;
|
||||
|
||||
const modelClassName = modelInput.value.trim();
|
||||
if (modelClassName.length === 0) return;
|
||||
|
||||
const data = new FormData();
|
||||
data.append('Generator[modelNs]', modelNs)
|
||||
data.append('Generator[modelName]', modelClassName)
|
||||
data.append(yii.getCsrfParam(), yii.getCsrfToken());
|
||||
|
||||
// AJAX-запрос на получение атрибутов
|
||||
fetch('default/action?id=dictionary&name=GetAttributes', {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if(data.result) {
|
||||
if (attributesContainer) {
|
||||
attributesContainer.innerHTML = '';
|
||||
data.attributes.forEach(attr => {
|
||||
|
||||
let label = document.createElement('label');
|
||||
label.className = 'checkbox-label';
|
||||
|
||||
let checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.name = 'Generator[attributes][]';
|
||||
checkbox.value = attr;
|
||||
|
||||
label.appendChild(checkbox);
|
||||
label.appendChild(document.createTextNode(' ' + attr));
|
||||
attributesContainer.appendChild(label);
|
||||
attributesContainer.appendChild(document.createElement('br'));
|
||||
});
|
||||
}
|
||||
|
||||
controllerInput.value = data.controller_id;
|
||||
generateMigrationName(data.controller_id);
|
||||
}
|
||||
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
function generateMigrationName(controllerId) {
|
||||
let migrationNameInput = document.querySelector('#generator-migrationname');
|
||||
// Получаем текущие дата и время
|
||||
const now = new Date();
|
||||
|
||||
// Форматируем дату и время в виде "yymmdd_hhmmss"
|
||||
const year = now.getFullYear().toString().slice(-2);
|
||||
const month = ('0' + (now.getMonth() + 1)).slice(-2);
|
||||
const day = ('0' + now.getDate()).slice(-2);
|
||||
const hours = ('0' + now.getHours()).slice(-2);
|
||||
const minutes = ('0' + now.getMinutes()).slice(-2);
|
||||
const seconds = ('0' + now.getSeconds()).slice(-2);
|
||||
|
||||
const timestamp = `${year}${month}${day}_${hours}${minutes}${seconds}`;
|
||||
|
||||
// Модифицируем имя таблицы: заменяем дефисы на подчеркивания, убираем расширения
|
||||
// Предположим, что tableName — это строка с дефисами, например: "furniture-packs"
|
||||
const formattedName = controllerId.replace(/-/g, '_');
|
||||
|
||||
migrationNameInput.value = `m${timestamp}_insert_${formattedName}_permissions`;
|
||||
}
|
||||
|
||||
})();
|
||||
53
src/default/_search.php
Normal file
53
src/default/_search.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating the controller class of a specified model.
|
||||
*/
|
||||
|
||||
/** @var yii\web\View $this */
|
||||
/** @var \drobnitsa\dictionaryGenerator\Generator $generator */
|
||||
/** @var string $controllerNs controller namespace */
|
||||
/** @var string $controllerName controller name */
|
||||
/** @var string $modelName model name */
|
||||
/** @var string $modelClass model class */
|
||||
/** @var string[] $attributes attributes to render */
|
||||
|
||||
|
||||
echo "<?php\n";
|
||||
?>
|
||||
use yii\helpers\Html;
|
||||
use common\widgets\ActiveForm;
|
||||
|
||||
/* @var $this yii\web\View */
|
||||
/* @var $model common\models\Addition */
|
||||
/* @var $form yii\widgets\ActiveForm */
|
||||
|
||||
?>
|
||||
|
||||
<div class="form-search">
|
||||
|
||||
<?= "<?php " ?>
|
||||
$form = ActiveForm::begin([
|
||||
'action' => ['index'],
|
||||
'method' => 'get',
|
||||
]); ?>
|
||||
|
||||
<div class="row search-block">
|
||||
<?php foreach ($attributes as $attribute) : ?>
|
||||
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
|
||||
<?= "<?= " ?> $form->field($model, '<?= $attribute ?>')->textInput(['maxlength' => true]) ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="" class="control-label"> </label>
|
||||
<div class="input-group">
|
||||
<?= "<?= " ?> Html::submitButton('<i class="fa fa-trash"></i>', ['class' => 'btn btn-default btn-outline-dark', 'title' => 'Очистить', 'onclick' => "var form = jQuery(this.form); form.find('input[type=text]').val(''); form.find('select').val(0); return true;"]) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= "<?php " ?> ActiveForm::end(); ?>
|
||||
<hr/>
|
||||
</div>
|
||||
24
src/default/controller.php
Normal file
24
src/default/controller.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating the controller class of a specified model.
|
||||
*/
|
||||
|
||||
/** @var yii\web\View $this */
|
||||
/** @var \drobnitsa\dictionaryGenerator\Generator $generator */
|
||||
/** @var string $controllerNs controller namespace */
|
||||
/** @var string $controllerName controller name */
|
||||
/** @var string $modelName model name */
|
||||
/** @var string $modelClass model class */
|
||||
|
||||
|
||||
echo "<?php\n";
|
||||
?>
|
||||
declare(strict_types=1);
|
||||
namespace <?= $controllerNs ?>;
|
||||
|
||||
use <?= $modelClass ?>;
|
||||
|
||||
class <?= $controllerName.'Controller' ?> extends AjaxController
|
||||
{
|
||||
public string $modelClass = <?= $modelName ?>::class;
|
||||
}
|
||||
31
src/default/migration.php
Normal file
31
src/default/migration.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating the controller class of a specified model.
|
||||
*/
|
||||
|
||||
/** @var yii\web\View $this */
|
||||
/** @var \drobnitsa\dictionaryGenerator\Generator $generator */
|
||||
/** @var string $moduleId module id */
|
||||
/** @var string $controllerId controller id */
|
||||
/** @var string $migrationName migration name */
|
||||
|
||||
echo "<?php\n";
|
||||
?>
|
||||
|
||||
use backend\modules\rbac\migrations\BasePermissionsMigration;
|
||||
|
||||
class <?= $migrationName ?> extends BasePermissionsMigration
|
||||
{
|
||||
function configure()
|
||||
{
|
||||
$this->moduleId = '<?= $moduleId ?>';
|
||||
$this->controllerId = '<?= $controllerId ?>';
|
||||
$this->actions = $this->defaultActions;
|
||||
$this->baseAction = 'index';
|
||||
$this->childrenMap = [
|
||||
'create' => [
|
||||
'edit'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
85
src/default/view.php
Normal file
85
src/default/view.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the template for generating the controller class of a specified model.
|
||||
*/
|
||||
|
||||
/** @var yii\web\View $this */
|
||||
/** @var \drobnitsa\dictionaryGenerator\Generator $generator */
|
||||
/** @var string $controllerNs controller namespace */
|
||||
/** @var string $controllerName controller name */
|
||||
/** @var string $modelName model name */
|
||||
/** @var string $modelClass model class */
|
||||
/** @var string[] $attributes attributes to render */
|
||||
|
||||
|
||||
echo "<?php\n";
|
||||
?>
|
||||
|
||||
use backend\assets\EditableFieldsAsset;
|
||||
use <?= $modelClass ?>;
|
||||
use common\grid\GridView;
|
||||
use common\widgets\Card;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
use yii\widgets\Pjax;
|
||||
|
||||
/* @var $this yii\web\View */
|
||||
/* @var $searchModel <?= $modelClass ?> */
|
||||
/* @var $dataProvider yii\data\ActiveDataProvider */
|
||||
|
||||
EditableFieldsAsset::register($this);
|
||||
$page = Yii::$app->request->getQueryParams()['page'] ?? 1;
|
||||
|
||||
$can_create = Yii::$app->user->can("backend_{$this->context->id}_create");
|
||||
$can_update = Yii::$app->user->can("backend_{$this->context->id}_edit");
|
||||
$can_delete = Yii::$app->user->can("backend_{$this->context->id}_delete");
|
||||
|
||||
$this->title = Yii::$app->urlManager->getLastTitle();
|
||||
?>
|
||||
|
||||
<?= "<?= " ?> $this->render('_search', ['model' => $searchModel]); ?>
|
||||
|
||||
|
||||
<?= "<?php " ?>Card::begin([]); ?>
|
||||
<?= "<?php " ?>Pjax::begin(['id' => 'pjax']) ?>
|
||||
|
||||
<?= "<?= " ?> GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'createRowModel' => new <?= $modelName ?>(),
|
||||
'formatter' => ['class' => 'yii\i18n\Formatter','nullDisplay' => ''],
|
||||
'filterSelector' => '.search-block *[name]',
|
||||
'tableOptions' => ['class' => 'table align-middle table-check table-bordered mb-0 editable-fields', 'data-base_url' => $this->context->id, 'id' => 'table-'.$this->context->id],
|
||||
'actions' => common\widgets\ActionButtons::widget(['defaultShowTitle' => false, 'defaultAccess' => '$', 'items' => [
|
||||
['name' => 'create', 'access' => $can_create, 'options' => ['class' => 'btn btn-success btn-sm btn-row-add', 'data-id' => 0], 'title' => 'Добавить', 'iconClass' => 'fa fa-plus'],
|
||||
$page > 0 ?
|
||||
['name' => Url::current(['page' => -1]), 'options' => ['class' => 'btn btn-primary btn-sm'], 'title' => 'Показать все', 'iconClass' => 'fa fa-expand'] :
|
||||
['name' => Url::current(['page' => 1]), 'options' => ['class' => 'btn btn-primary btn-sm'], 'title' => 'Показать постранично', 'iconClass' => 'fa fa-compress'],
|
||||
]]),
|
||||
'columns' => [
|
||||
[
|
||||
'class' => 'yii\grid\SerialColumn',
|
||||
'header' => '№',
|
||||
],
|
||||
<?php foreach($attributes as $attribute) : ?>
|
||||
[
|
||||
'attribute' => '<?= $attribute ?>',
|
||||
'format' => 'raw',
|
||||
'value' => function($model) use ($can_update) {
|
||||
return $can_update ? Html::input('text', '<?= $attribute ?>', $model-><?= $attribute ?>, ['class' => 'form-control', 'required' => 1]) : $model-><?= $attribute ?>;
|
||||
},
|
||||
],
|
||||
<?php endforeach; ?>
|
||||
[
|
||||
'class' => 'common\grid\ActionColumn',
|
||||
'defaultShowTitle' => false,
|
||||
'visible' => $can_delete,
|
||||
'buttons' => [
|
||||
'delete' => ['icon' => 'fa fa-trash', 'class' => 'btn btn-danger btn-sm btn-row-remove', 'title' => 'Удаление'],
|
||||
],
|
||||
]
|
||||
],
|
||||
]);
|
||||
?>
|
||||
|
||||
<?= "<?php " ?> Pjax::end() ?>
|
||||
<?= "<?php " ?> Card::end(); ?>
|
||||
35
src/form.php
Normal file
35
src/form.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use drobnitsa\dictionaryGenerator\Generator;
|
||||
use drobnitsa\dictionaryGenerator\assets\MainAsset;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\widgets\ActiveForm;
|
||||
|
||||
/* @var $generator Generator */
|
||||
/* @var $this yii\web\View */
|
||||
/* @var yii\widgets\ActiveForm $form */
|
||||
|
||||
MainAsset::register($this);
|
||||
|
||||
|
||||
$modelAttributes = $generator->getModelAttributes(false);
|
||||
|
||||
?>
|
||||
|
||||
<?= $form->field($generator, 'modelNs') ?>
|
||||
|
||||
<?= $form->field($generator, 'modelName')->textInput(['placeholder' => 'PostRecord']) ?>
|
||||
|
||||
<?= $form->field($generator, 'moduleId') ?>
|
||||
|
||||
<?= $form->field($generator, 'controllerId')->textInput(['placeholder' => 'post-records']) ?>
|
||||
|
||||
<?= $form->field($generator, 'attributes')->checkboxList($modelAttributes, ['separator' => '<br>']) ?>
|
||||
|
||||
<?= $form->field($generator, 'generateMigration')->checkbox() ?>
|
||||
|
||||
<?= $form->field($generator, 'migrationNs') ?>
|
||||
|
||||
<?= $form->field($generator, 'migrationName')->textInput(['placeholder' => 'm250907_112925_insert_furniture_packs_permissions']) ?>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user