diff --git a/config/admin.php b/config/admin.php
index 7e94a437..39c32042 100644
--- a/config/admin.php
+++ b/config/admin.php
@@ -30,25 +30,27 @@
'auth' => [
// 是否开启验证码
- 'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true),
+ 'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true),
// 是否开启认证
- 'enable' => true,
+ 'enable' => true,
// 是否开启鉴权
- 'permission' => true,
- 'guard' => 'admin',
- 'guards' => [
+ 'permission' => true,
+ // token 有效期 (分钟), 为空则不限时
+ 'token_expiration' => null,
+ 'guard' => 'admin',
+ 'guards' => [
'admin' => [
'driver' => 'sanctum',
'provider' => 'admin',
],
],
- 'providers' => [
+ 'providers' => [
'admin' => [
'driver' => 'eloquent',
'model' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
],
],
- 'except' => [
+ 'except' => [
],
],
diff --git a/src/AdminServiceProvider.php b/src/AdminServiceProvider.php
index eba60e9a..4a3a046d 100644
--- a/src/AdminServiceProvider.php
+++ b/src/AdminServiceProvider.php
@@ -9,7 +9,7 @@
use Psr\Container\NotFoundExceptionInterface;
use Psr\Container\ContainerExceptionInterface;
use Slowlyo\OwlAdmin\Models\PersonalAccessToken;
-use Slowlyo\OwlAdmin\Support\{Context, Cores\Menu, Cores\Asset, Cores\Module};
+use Slowlyo\OwlAdmin\Support\{Context, Cores\Menu, Cores\Asset, Cores\Module, Cores\Relationships};
class AdminServiceProvider extends ServiceProvider
{
@@ -78,6 +78,8 @@ public function boot(): void
$this->loadRoutes();
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
$this->usePersonalAccessTokenModel();
+
+ Relationships::loader();
}
protected function loadBaseRoute()
diff --git a/src/Controllers/AdminRoleController.php b/src/Controllers/AdminRoleController.php
index ee812cfe..558fc639 100644
--- a/src/Controllers/AdminRoleController.php
+++ b/src/Controllers/AdminRoleController.php
@@ -77,6 +77,7 @@ protected function setPermission()
->name('permissions')
->label()
->multiple()
+ ->heightAuto()
->options(AdminPermissionService::make()->getTree())
->searchable()
->cascade()
diff --git a/src/Controllers/DevTools/RelationshipController.php b/src/Controllers/DevTools/RelationshipController.php
index b16b1c6e..b0545e9f 100644
--- a/src/Controllers/DevTools/RelationshipController.php
+++ b/src/Controllers/DevTools/RelationshipController.php
@@ -2,15 +2,14 @@
namespace Slowlyo\OwlAdmin\Controllers\DevTools;
-use Illuminate\Support\Str;
use Illuminate\Support\Facades\Schema;
-use Illuminate\Database\Eloquent\Model;
-use Slowlyo\OwlAdmin\Support\Cores\Module;
use Slowlyo\OwlAdmin\Models\AdminRelationship;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use Slowlyo\OwlAdmin\Services\AdminRelationshipService;
-use Spatie\LaravelIgnition\Support\Composer\ComposerClassMap;
+/**
+ * @property AdminRelationshipService $service
+ */
class RelationshipController extends AdminController
{
protected string $serviceName = AdminRelationshipService::class;
@@ -22,13 +21,16 @@ public function list()
->headerToolbar([
$this->createButton(true, 'lg'),
...$this->baseHeaderToolBar(),
+ $this->modelGenerator(),
])
->columns([
amis()->TableColumn('id', 'ID')->sortable(),
+ amis()->TableColumn('model', '模型')->searchable(),
amis()->TableColumn('title', '名称')->searchable(),
- amis()->TableColumn('sign', '标识')->searchable(),
+ amis()->TableColumn('remark', '备注')->searchable(),
$this->rowActions([
- $this->rowEditButton(true),
+ $this->previewButton(),
+ $this->rowEditButton(true, 'lg'),
$this->rowDeleteButton(),
]),
]);
@@ -36,6 +38,60 @@ public function list()
return $this->baseList($crud);
}
+ public function modelGenerator()
+ {
+ return amis()->DrawerAction()->label('生成模型')->level('success')->drawer(
+ amis()->Drawer()
+ ->title('生成模型')
+ ->size('lg')
+ ->resizable()
+ ->closeOnOutside()
+ ->closeOnEsc()
+ ->actions([
+ amis()->VanillaAction()->label('生成')->actionType('submit')->level('primary'),
+ ])
+ ->body([
+ amis()->Form()
+ ->api('/dev_tools/relation/generate_model')
+ ->initApi('/dev_tools/relation/all_models')
+ ->mode('normal')
+ ->body([
+ amis()->TreeControl()
+ ->name('check_tables')
+ ->label()
+ ->multiple()
+ ->heightAuto()
+ ->required()
+ ->source('${all_models}')
+ ->searchable()
+ ->joinValues(false)
+ ->extractValue()
+ ->size('full')
+ ->className('h-full b-none')
+ ->inputClassName('h-full tree-full')
+ ->set('menuTpl', '${label} ${model}'),
+ ]),
+ ])
+ );
+ }
+
+ public function previewButton()
+ {
+ return amis()->DrawerAction()->label('预览')->level('link')->icon('fa fa-eye')->drawer(
+ amis()->Drawer()
+ ->position('top')
+ ->resizable()
+ ->title('预览')
+ ->actions([])
+ ->showCloseButton(false)
+ ->closeOnEsc()
+ ->closeOnOutside()
+ ->body(
+ amis()->Code()->value('${preview_code | raw}')->language('php')
+ )
+ );
+ }
+
public function form()
{
$modelSelect = function ($name, $label) {
@@ -47,7 +103,26 @@ public function form()
->searchable();
};
- return $this->baseForm()->body([
+ $columnSelect = function ($name, $label, $modelField = "_blank_model", $tableField = '_blank_table') {
+ return amis()
+ ->TextControl($name, $label)
+ ->source('/dev_tools/relation/column_options?model=${' . $modelField . '}&table=${' . $tableField . '}');
+ };
+
+ $args = function ($type, $items) {
+ return amis()
+ ->ComboControl('args', '参数')
+ ->multiLine()
+ ->strictMode(false)
+ ->items($items)
+ ->visibleOn('${type == "' . $type . '"}');
+ };
+
+ return $this->baseForm()->data([
+ 'tables' => collect(json_decode(json_encode(Schema::getAllTables()), true))
+ ->map(fn($i) => array_shift($i))
+ ->toArray(),
+ ])->body([
amis()->GroupControl()->body([
amis()->GroupControl()->direction('vertical')->body([
$modelSelect('model', '模型'),
@@ -60,88 +135,88 @@ public function form()
->options(AdminRelationship::typeOptions()),
]),
// 一对一
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_HAS_ONE, [
// $related, $foreignKey = null, $localKey = null
$modelSelect('related', '关联模型'),
- amis()->TextControl('foreignKey', 'foreignKey'),
- amis()->TextControl('localKey', 'localKey'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_HAS_ONE . '"}'),
+ $columnSelect('foreignKey', 'foreignKey', 'related'),
+ $columnSelect('localKey', 'localKey', 'model'),
+ ]),
// 一对多
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_HAS_MANY, [
// $related, $foreignKey = null, $localKey = null
$modelSelect('related', '关联模型'),
- amis()->TextControl('foreignKey', 'foreignKey'),
- amis()->TextControl('localKey', 'localKey'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_HAS_MANY . '"}'),
+ $columnSelect('foreignKey', 'foreignKey', 'related'),
+ $columnSelect('localKey', 'localKey', 'model'),
+ ]),
// 一对多(反向)/属于
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_BELONGS_TO, [
// $related, $foreignKey = null, $ownerKey = null, $relation = null
$modelSelect('related', '关联模型'),
- amis()->TextControl('foreignKey', 'foreignKey'),
- amis()->TextControl('ownerKey', 'ownerKey'),
+ $columnSelect('foreignKey', 'foreignKey', 'model'),
+ $columnSelect('ownerKey', 'ownerKey', 'related'),
amis()->TextControl('relation', 'relation'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_BELONGS_TO . '"}'),
+ ]),
// 多对多
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_BELONGS_TO_MANY, [
// $related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null, $relation = null
$modelSelect('related', '关联模型'),
- amis()->TextControl('table', 'table'),
- amis()->TextControl('foreignPivotKey', 'foreignPivotKey'),
- amis()->TextControl('relatedPivotKey', 'relatedPivotKey'),
- amis()->TextControl('parentKey', 'parentKey'),
- amis()->TextControl('relatedKey', 'relatedKey'),
+ amis()->SelectControl('table', 'table')->source('${tables}')->searchable(),
+ $columnSelect('foreignPivotKey', 'foreignPivotKey', '_blank_model', 'table'),
+ $columnSelect('relatedPivotKey', 'relatedPivotKey', '_blank_model', 'table'),
+ $columnSelect('parentKey', 'parentKey', 'model'),
+ $columnSelect('relatedKey', 'relatedKey', 'related'),
amis()->TextControl('relation', 'relation'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_BELONGS_TO_MANY . '"}'),
+ ]),
// 远程一对一
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_HAS_ONE_THROUGH, [
// $related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null
$modelSelect('related', '关联模型'),
$modelSelect('through', '中间模型'),
- amis()->TextControl('firstKey', 'firstKey'),
- amis()->TextControl('secondKey', 'secondKey'),
- amis()->TextControl('localKey', 'localKey'),
- amis()->TextControl('secondLocalKey', 'secondLocalKey'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_HAS_ONE_THROUGH . '"}'),
+ $columnSelect('firstKey', 'firstKey', 'through'),
+ $columnSelect('secondKey', 'secondKey', 'related'),
+ $columnSelect('localKey', 'localKey', 'model'),
+ $columnSelect('secondLocalKey', 'secondLocalKey', 'through'),
+ ]),
// 远程一对多
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_HAS_MANY_THROUGH, [
// $related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null
$modelSelect('related', '关联模型'),
$modelSelect('through', '中间模型'),
- amis()->TextControl('firstKey', 'firstKey'),
- amis()->TextControl('secondKey', 'secondKey'),
- amis()->TextControl('localKey', 'localKey'),
- amis()->TextControl('secondLocalKey', 'secondLocalKey'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_HAS_MANY_THROUGH . '"}'),
+ $columnSelect('firstKey', 'firstKey', 'through'),
+ $columnSelect('secondKey', 'secondKey', 'related'),
+ $columnSelect('localKey', 'localKey', 'model'),
+ $columnSelect('secondLocalKey', 'secondLocalKey', 'through'),
+ ]),
// 一对一(多态)
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_MORPH_ONE, [
// $related, $name, $type = null, $id = null, $localKey = null
$modelSelect('related', '关联模型'),
amis()->TextControl('name', 'name')->required(),
amis()->TextControl('type', 'type'),
amis()->TextControl('id', 'id'),
- amis()->TextControl('localKey', 'localKey'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_MORPH_ONE . '"}'),
+ $columnSelect('localKey', 'localKey', 'model'),
+ ]),
// 一对多(多态)
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_MORPH_MANY, [
// $related, $name, $type = null, $id = null, $localKey = null
$modelSelect('related', '关联模型'),
amis()->TextControl('name', 'name')->required(),
amis()->TextControl('type', 'type'),
amis()->TextControl('id', 'id'),
- amis()->TextControl('localKey', 'localKey'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_MORPH_MANY . '"}'),
+ $columnSelect('localKey', 'localKey', 'model'),
+ ]),
// 多对多(多态)
- amis()->ComboControl('args', '参数')->multiLine()->items([
+ $args(AdminRelationship::TYPE_MORPH_TO_MANY, [
// $related, $name, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null, $inverse = false
$modelSelect('related', '关联模型'),
amis()->TextControl('name', 'name')->required(),
- amis()->TextControl('table', 'table'),
- amis()->TextControl('foreignPivotKey', 'foreignPivotKey'),
- amis()->TextControl('relatedPivotKey', 'relatedPivotKey'),
- amis()->TextControl('parentKey', 'parentKey'),
- amis()->TextControl('relatedKey', 'relatedKey'),
+ amis()->SelectControl('table', 'table')->source('${tables}')->searchable(),
+ $columnSelect('foreignPivotKey', 'foreignPivotKey', '_blank_model', 'table'),
+ $columnSelect('relatedPivotKey', 'relatedPivotKey', '_blank_model', 'table'),
+ $columnSelect('parentKey', 'parentKey', 'model'),
+ $columnSelect('relatedKey', 'relatedKey', 'related'),
amis()->TextControl('inverse', 'inverse'),
- ])->visibleOn('${type == "' . AdminRelationship::TYPE_MORPH_TO_MANY . '"}'),
+ ]),
]),
]);
}
@@ -153,31 +228,82 @@ public function detail($id)
}
/**
- * 获取所有已经加载的 model
+ * 获取所有 model
*
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
*/
public function modelOptions()
{
- $composer = require base_path('/vendor/autoload.php');
- $classMap = $composer->getClassMap();
-
- $tables = collect(json_decode(json_encode(Schema::getAllTables()), true))
- ->map(fn($i) => array_shift($i))
- ->toArray();
-
- $models = collect($classMap)
- ->keys()
- ->filter(fn($item) => str_contains($item, 'Models\\'))
- ->filter(fn($item) => (new \ReflectionClass($item))->isSubclassOf(Model::class))
- ->filter(fn($item) => in_array(app($item)->getTable(), $tables))
- ->values()
- ->map(fn($item) => [
- 'label' => Str::of($item)->explode('\\')->pop(),
- 'table' => app($item)->getTable(),
- 'value' => $item,
- ]);
+ $models = $this->service->allModels()['models'];
return $this->response()->success($models);
}
+
+ /**
+ * 字段选项
+ *
+ * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
+ */
+ public function columnOptions()
+ {
+ $model = request('model');
+ $table = request('table');
+
+ if (blank($model) && blank($table)) {
+ return $this->response()->success([]);
+ }
+
+ $table = $table ?: app($model)->getTable();
+
+ $columns = Schema::getColumnListing($table);
+
+ return $this->response()->success($columns);
+ }
+
+ /**
+ * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
+ */
+ public function allModels()
+ {
+ $all = $this->service->allModels();
+ $tables = $all['tables'];
+ $models = collect($all['models'])->keyBy('table');
+
+ $all_models = collect($tables)->map(function ($item) use ($models) {
+ $model = data_get($models, $item . '.value');
+
+ return [
+ 'value' => $item,
+ 'label' => $item,
+ 'model' => $model,
+ 'disabled' => (bool)$model,
+ ];
+ })->sortBy('disabled')->values();
+
+ return $this->response()->success(compact('all_models'));
+ }
+
+ /**
+ * 生成模型
+ *
+ * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource
+ */
+ public function generateModel()
+ {
+ $tables = request('check_tables');
+ $existsList = collect($this->service->allModels()['models'])->pluck('table')->toArray();
+ $exists = array_intersect($tables, $existsList);
+
+ admin_abort_if(filled($exists), '模型已存在:' . implode(',', $exists));
+
+ try {
+ foreach ($tables as $table) {
+ $this->service->generateModel($table);
+ }
+ } catch (\Throwable $e) {
+ return $this->response()->fail($e->getMessage());
+ }
+
+ return $this->response()->successMessage(__('admin.action_success'));
+ }
}
diff --git a/src/Models/AdminRelationship.php b/src/Models/AdminRelationship.php
index a46c9079..ca31f1f3 100644
--- a/src/Models/AdminRelationship.php
+++ b/src/Models/AdminRelationship.php
@@ -2,6 +2,8 @@
namespace Slowlyo\OwlAdmin\Models;
+use Illuminate\Support\Str;
+use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Concerns\HasTimestamps;
class AdminRelationship extends BaseModel
@@ -64,11 +66,6 @@ class AdminRelationship extends BaseModel
self::TYPE_MORPH_TO_MANY => '多对多(多态)',
];
- public function aaa()
- {
- // $this->belongsTo();
- }
-
public static function typeOptions()
{
return collect(self::TYPE_MAP)->map(function ($item, $index) {
@@ -79,4 +76,47 @@ public static function typeOptions()
];
})->values();
}
+
+ public function method(): Attribute
+ {
+ return Attribute::get(fn() => self::TYPE_MAP[$this->type]);
+ }
+
+ public function buildArgs()
+ {
+ $reflection = new \ReflectionClass($this->model);
+ $params = $reflection->getMethod($this->method)->getParameters();
+
+ $args = [];
+
+ foreach ($params as $item) {
+ $_value = data_get($this->args, $item->getName());
+ $args[] = [
+ 'name' => $item->getName(),
+ 'value' => filled($_value) ? $_value : $item->getDefaultValue(),
+ ];
+ }
+
+ return $args;
+ }
+
+ public function getPreviewCode()
+ {
+ $className = Str::of($this->model)->explode('\\')->pop();
+ $args = collect($this->buildArgs())
+ ->pluck('value')
+ ->map(fn($item) => is_null($item) ? 'null' : (is_string($item) ? "'{$item}'" : $item))
+ ->implode(', ');
+
+ return <<title() {
+ return \$this->$this->method($args);
+ }
+}
+PHP;
+ }
}
diff --git a/src/Models/PersonalAccessToken.php b/src/Models/PersonalAccessToken.php
index a53094c0..5a9611ea 100644
--- a/src/Models/PersonalAccessToken.php
+++ b/src/Models/PersonalAccessToken.php
@@ -13,4 +13,26 @@ public function __construct(array $attributes = [])
parent::__construct($attributes);
}
+
+ public static function findToken($token)
+ {
+ $expiration = config('admin.auth.token_expiration');
+
+ if (!str_contains($token, '|')) {
+ return static::where('token', hash('sha256', $token))
+ ->when($expiration, fn($q) => $q->where('created_at', '>=', now()->subMinutes($expiration)))
+ ->first();
+ }
+
+ [$id, $token] = explode('|', $token, 2);
+
+ $instance = static::when($expiration, fn($q) => $q->where('created_at', '>=', now()->subMinutes($expiration)))
+ ->find($id);
+
+ if ($instance) {
+ return hash_equals($instance->token, hash('sha256', $token)) ? $instance : null;
+ }
+
+ return null;
+ }
}
diff --git a/src/Services/AdminRelationshipService.php b/src/Services/AdminRelationshipService.php
index c73d4251..2791ed21 100644
--- a/src/Services/AdminRelationshipService.php
+++ b/src/Services/AdminRelationshipService.php
@@ -2,6 +2,9 @@
namespace Slowlyo\OwlAdmin\Services;
+use Illuminate\Support\Str;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Slowlyo\OwlAdmin\Models\AdminRelationship;
@@ -14,4 +17,110 @@ class AdminRelationshipService extends AdminService
protected string $modelName = AdminRelationship::class;
public string $cacheKey = 'admin_relationships';
+
+ public function list()
+ {
+ $list = parent::list();
+
+ collect($list['items'])->transform(function ($item) {
+ $item->setAttribute('preview_code', $item->getPreviewCode());
+ });
+
+ return $list;
+ }
+
+ public function getAll()
+ {
+ return cache()->rememberForever($this->cacheKey, function () {
+ return self::query()->get();
+ });
+ }
+
+ public function saving(&$data, $primaryKey = '')
+ {
+ $exists = self::query()
+ ->where('model', $data['model'])
+ ->where('title', $data['title'])
+ ->when($primaryKey, fn($q) => $q->where('id', '<>', $primaryKey))
+ ->exists();
+
+ admin_abort_if($exists, '该模型下存在同名关联');
+
+ $methodExists = method_exists($data['model'], $data['title']);
+
+ admin_abort_if($methodExists, '该模型下存在同名关联');
+ }
+
+ public function saved($model, $isEdit = false)
+ {
+ cache()->forget($this->cacheKey);
+ }
+
+ public function deleted($ids)
+ {
+ cache()->forget($this->cacheKey);
+ }
+
+ public function allModels()
+ {
+ $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(app_path('Models')));
+ $phpFiles = new \RegexIterator($iterator, '/^.+\.php$/i', \RegexIterator::GET_MATCH);
+
+ foreach ($phpFiles as $phpFile) {
+ $filePath = $phpFile[0];
+ require_once $filePath;
+ }
+
+ $modelDirClass = collect(get_declared_classes())
+ ->filter(fn($i) => Str::startsWith($i, 'App\\Models'))
+ ->toArray();
+
+ $composer = require base_path('/vendor/autoload.php');
+ $classMap = $composer->getClassMap();
+
+ $tables = collect(json_decode(json_encode(Schema::getAllTables()), true))
+ ->map(fn($i) => array_shift($i))
+ ->toArray();
+
+ $models = collect($classMap)
+ ->keys()
+ ->filter(fn($item) => str_contains($item, 'Models\\'))
+ ->filter(fn($item) => @class_exists($item))
+ ->filter(fn($item) => (new \ReflectionClass($item))->isSubclassOf(Model::class))
+ ->merge($modelDirClass)
+ ->unique()
+ ->filter(fn($item) => in_array(app($item)->getTable(), $tables))
+ ->values()
+ ->map(fn($item) => [
+ 'label' => Str::of($item)->explode('\\')->pop(),
+ 'table' => app($item)->getTable(),
+ 'value' => $item,
+ ]);
+
+ return compact('tables', 'models');
+ }
+
+ public function generateModel($table)
+ {
+ $className = Str::of($table)->studly()->singular()->value();
+
+ $template = <<put($path, $template);
+ }
}
diff --git a/src/Support/Cores/Relationships.php b/src/Support/Cores/Relationships.php
new file mode 100644
index 00000000..157f936b
--- /dev/null
+++ b/src/Support/Cores/Relationships.php
@@ -0,0 +1,28 @@
+getAll();
+
+ if (blank($relationships)) {
+ return;
+ }
+
+ foreach ($relationships as $relationship) {
+ try {
+ $relationship->model::resolveRelationUsing($relationship->title, function ($model) use ($relationship) {
+ $method = $relationship->method;
+
+ return $model->$method(...array_column($relationship->buildArgs(), 'value'));
+ });
+ }catch (\Throwable $e) {
+ }
+ }
+ }
+}
diff --git a/src/Support/Cores/Route.php b/src/Support/Cores/Route.php
index ea9006aa..bc5bd2b3 100644
--- a/src/Support/Cores/Route.php
+++ b/src/Support/Cores/Route.php
@@ -108,6 +108,9 @@ private static function baseRoutes($prefix)
$router->resource('relationships', RelationshipController::class);
$router->group(['prefix' => 'relation'], function (Router $router) {
$router->get('model_options', [RelationshipController::class, 'modelOptions']);
+ $router->get('column_options', [RelationshipController::class, 'columnOptions']);
+ $router->get('all_models', [RelationshipController::class, 'allModels']);
+ $router->post('generate_model', [RelationshipController::class, 'generateModel']);
});
});
}