├── .gitignore
├── .styleci.yml
├── .travis.yml
├── LICENSE
├── changelog.md
├── composer.json
├── config
└── laravel-generator.php
├── contributing.md
├── phpunit.xml
├── readme.md
├── readme_zh_CN.md
├── resources
├── assets
│ ├── css
│ │ ├── element.css
│ │ └── fonts
│ │ │ ├── element-icons.ttf
│ │ │ └── element-icons.woff
│ ├── images
│ │ └── logo.png
│ ├── js
│ │ ├── axios.js
│ │ ├── element-2.4.js
│ │ └── vue.js
│ └── vs
│ │ ├── base
│ │ └── worker
│ │ │ └── workerMain.js
│ │ ├── basic-languages
│ │ └── java
│ │ │ └── java.js
│ │ ├── editor
│ │ ├── editor.main.css
│ │ ├── editor.main.js
│ │ ├── editor.main.nls.de.js
│ │ ├── editor.main.nls.es.js
│ │ ├── editor.main.nls.fr.js
│ │ ├── editor.main.nls.it.js
│ │ ├── editor.main.nls.ja.js
│ │ ├── editor.main.nls.js
│ │ ├── editor.main.nls.ko.js
│ │ ├── editor.main.nls.ru.js
│ │ ├── editor.main.nls.zh-cn.js
│ │ └── editor.main.nls.zh-tw.js
│ │ ├── language
│ │ ├── css
│ │ │ ├── cssMode.js
│ │ │ └── cssWorker.js
│ │ ├── html
│ │ │ ├── htmlMode.js
│ │ │ └── htmlWorker.js
│ │ ├── json
│ │ │ ├── jsonMode.js
│ │ │ └── jsonWorker.js
│ │ └── typescript
│ │ │ ├── tsMode.js
│ │ │ └── tsWorker.js
│ │ └── loader.js
├── lang
│ ├── en
│ │ └── generator.php
│ └── zh_CN
│ │ └── generator.php
├── migrations
│ └── 2025_04_11_095115_create_laravel_generators_table.php
└── views
│ ├── generator.blade.php
│ ├── generator_logs.blade.php
│ ├── generator_migrate.blade.php
│ ├── index.blade.php
│ ├── layout.blade.php
│ ├── template_lists.blade.php
│ └── template_update.blade.php
├── routes
└── route.php
├── src
├── Console
│ └── InstallCommand.php
├── Controllers
│ ├── AssetController.php
│ ├── GeneratorController.php
│ └── GeneratorTemplateController.php
├── Database
│ └── GeneratorSeeder.php
├── FileCreator.php
├── GeneratorServiceProvider.php
├── GeneratorUtils.php
├── Message.php
├── MigrationCreator.php
└── Models
│ ├── LaravelGenerator.php
│ ├── LaravelGeneratorConfig.php
│ ├── LaravelGeneratorLog.php
│ └── LaravelGeneratorType.php
└── tests
├── GeneratorUtilsTest.php
└── LaravelGeneratorLogTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.lock
3 | .idea/*
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: laravel
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | php:
3 | - '7.0'
4 | - '7.1'
5 | - '7.2'
6 | - nightly
7 |
8 | sudo: false
9 | matrix:
10 | fast_finish: true
11 |
12 | before_script:
13 | - travis_retry composer self-update
14 | - travis_retry composer install --no-interaction
15 |
16 | script:
17 | - vendor/bin/phpunit
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) foryoufeng
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to `laravel-generator` will be documented in this file.
4 |
5 | * # Version 4.0
6 | **更新时间:2025-06-04**
7 |
8 | 更新日志
9 |
10 | * Modified the template engine to blade and changed the default template content / 修改模板引擎为blade,并修改默认模板内容
11 | * Changed the configuration of the `laravel-generator.php` configuration file / 更改配置文件`laravel-generator.php`的配置
12 | * Added template migration for existing tables. / 增加已存在表的模板迁移
13 |
14 | * # Version 3.0
15 | * Added support for Laravel 12+ / 增加对Laravel 12+ 的支持
16 | * Added a record/log panel. / 添加生成记录面板
17 | * Modified the default template to Vue 3. / 修改默认模板为vue3
18 | ---
19 |
20 | * # Version 2.6
21 | * Added support for Laravel 10+ / 增加对Laravel 10+ 的支持
22 |
23 | ---
24 |
25 | * # Version 2.6
26 | * Added support for Laravel 9+ / 增加对Laravel 9+ 的支持
27 | * fix the add create:migrate bug / 修复创建迁移文件报错bug
28 | * fix the change migrate bug / 修复修改migrate表结构字段报错的bug
29 | ---
30 |
31 | * # Version 2.1
32 | * Added support for Laravel 6+ / 增加对Laravel 6+ 的支持
33 | * fix the primary key add bug / 修复新增字段为主键时引起的报错bug
34 | * fix the migrate show error cause by add two or more filed / 修复migrate板块添加多个字段时服务器报错的bug
35 | * fix the Relationships show error cause by add two or more relationship in the generator/ 修复generator板块中添加多个关联关系时服务器报错的bug
36 | * add some fields such as display name and rule and so on /新增显示名称、规则等字段
37 | ---
38 |
39 | * # Version 2.0
40 | * add tables / 添加数据表
41 | * add templates and can edit/add / 增加模板,可以进行添加和编辑
42 | * add Foreign and Relationships / 增加外键和关联关系
43 | * add some fields such as display name and rule and so on /新增显示名称、规则等字段
44 | ---
45 | * # Version 1.0
46 |
47 | ### Added
48 | - First version. / 第一个版本
49 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "foryoufeng/laravel-generator",
3 | "description": "A tool for generate Laravel code file",
4 | "license": "MIT",
5 | "authors": [
6 | {
7 | "name": "foryoufeng",
8 | "email": "foryoufeng@gmail.com",
9 | "homepage": "https://github.com/foryoufeng"
10 | }
11 | ],
12 | "homepage": "https://github.com/foryoufeng/laravel-generator",
13 | "keywords": ["Laravel", "laravel-generator","code generator"],
14 | "require": {
15 | "laravel/framework": "~9.0||~10.0||~11.0||~12.0",
16 | "doctrine/dbal": "^4.2"
17 | },
18 | "require-dev": {
19 | "roave/security-advisories": "dev-latest"
20 | },
21 | "autoload": {
22 | "psr-4": {
23 | "Foryoufeng\\Generator\\": "src/"
24 | }
25 | },
26 | "autoload-dev": {
27 | "psr-4": {
28 | "Foryoufeng\\Generator\\Tests\\": "tests"
29 | }
30 | },
31 | "extra": {
32 | "laravel": {
33 | "providers": [
34 | "Foryoufeng\\Generator\\GeneratorServiceProvider"
35 | ]
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/config/laravel-generator.php:
--------------------------------------------------------------------------------
1 | 'Laravel Generator',
5 | // the url to access
6 | 'route'=>'laravel-generator',
7 | // the rule can be used by the field
8 | 'rules'=>[
9 | 'string',
10 | 'email',
11 | 'file',
12 | 'numeric',
13 | 'array',
14 | 'alpha',
15 | 'alpha_dash',
16 | 'alpha_num',
17 | 'date',
18 | 'boolean',
19 | 'distinct',
20 | 'phone',
21 | 'custom'
22 | ],
23 | 'custom_keys'=>[
24 | 'author'=>env('GENERATOR_AUTHOR','system')
25 | ]
26 | ];
27 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are welcome and will be fully credited.
4 |
5 | Contributions are accepted via Pull Requests on [Github](https://github.com/foryoufeng/laravel-generator).
6 |
7 | # Things you could do
8 | If you want to contribute but do not know where to start, this list provides some starting points.
9 | - Add license text
10 | - Remove rewriteRules.php
11 | - Set up TravisCI, StyleCI, ScrutinizerCI
12 | - Write a comprehensive ReadMe
13 |
14 | ## Pull Requests
15 |
16 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests.
17 |
18 | - **Document any change in behaviour** - Make sure the `readme.md` and any other relevant documentation are kept up-to-date.
19 |
20 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
21 |
22 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
23 |
24 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
25 |
26 |
27 | **Happy coding**!
28 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | ./tests/
15 |
16 |
17 |
18 |
19 | src/
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | # Laravel Generator
12 | ## [中文文档](readme_zh_CN.md)
13 | A graphical interface code generator for quickly generating code for Laravel applications.
14 |
15 |
16 | # Installation
17 |
18 | If you have PHP and Composer installed, you can install the Laravel installer via Composer:
19 |
20 | ```bash
21 | composer require --dev foryoufeng/laravel-generator
22 | ```
23 |
24 | Run the following command to install the code generator:
25 |
26 | ```
27 | php artisan generator:install
28 | ```
29 |
30 | Add the creator's information in the `.env` file:
31 | ```sh
32 | GENERATOR_AUTHOR=Your Name
33 | ```
34 |
35 | Now you can access your application URL `http://localhost:8000/laravel-generator` to use `laravel-generator`.
36 |
37 | ## Configuration file
38 |
39 | Publish configuration file
40 |
41 | ```sh
42 | php artisan vendor:publish --tag=laravel-generator
43 | ```
44 |
45 | `generator.php` file description:
46 |
47 | ```php
48 | 'Laravel Generator',
51 | // the url to access
52 | 'route'=>'laravel-generator',
53 | // Define rules
54 | 'rules' => [
55 | 'string',
56 | 'email',
57 | 'file',
58 | 'numeric',
59 | 'array',
60 | 'alpha',
61 | 'alpha_dash',
62 | 'alpha_num',
63 | 'date',
64 | 'boolean',
65 | 'distinct',
66 | 'phone',
67 | 'custom'
68 | ],
69 | // Custom parameters
70 | 'custom_keys'=>[
71 | 'author'=>env('GENERATOR_AUTHOR','system')
72 | ]
73 | ];
74 | ```
75 |
76 | ## Update Log
77 |
78 | View [changelog](changelog.md) for update logs.
79 |
80 | MIT. Please see the [license file](license.md) for more information.
81 |
--------------------------------------------------------------------------------
/readme_zh_CN.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | # Laravel Generator
12 | 为laravel应用快速生成代码的图形化界面代码生成器
13 |
14 |
15 | ## 安装
16 |
17 | 通过Composer
18 |
19 | ``` bash
20 | composer require --dev foryoufeng/laravel-generator
21 | ```
22 |
23 | 运行如下命令来安装代码生成器
24 |
25 | ```
26 | php artisan generator:install
27 | ```
28 |
29 | 在`.env`中添加配置创建人的信息
30 | ```sh
31 | GENERATOR_AUTHOR=你的名字
32 | ```
33 |
34 | 现在您可以访问您的应用url`http://localhost:8000/laravel-generator` 来使用`Laravel Generator`了
35 |
36 |
37 | ## 配置文件
38 |
39 | 发布配置文件
40 |
41 | ```sh
42 | php artisan vendor:publish --tag=laravel-generator
43 | ```
44 |
45 | `generator.php` 文件说明
46 |
47 | ```
48 | 'Laravel Generator',
52 | // 访问地址
53 | 'route'=>'laravel-generator',
54 | // 定义规则
55 | 'rules'=>[
56 | 'string',
57 | 'email',
58 | 'file',
59 | 'numeric',
60 | 'array',
61 | 'alpha',
62 | 'alpha_dash',
63 | 'alpha_num',
64 | 'date',
65 | 'boolean',
66 | 'distinct',
67 | 'phone',
68 | 'custom'
69 | ],
70 | //自定义参数
71 | 'custom_keys'=>[
72 | 'author'=>env('GENERATOR_AUTHOR','system')
73 | ]
74 | ];
75 | ```
76 |
77 | ## 更新记录
78 |
79 | 查看 [changelog](changelog.md) 获取更新记录
80 |
81 | MIT. Please see the [license file](license.md) for more information.
82 |
--------------------------------------------------------------------------------
/resources/assets/css/fonts/element-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/foryoufeng/laravel-generator/96a960d660ad8bf6f0955746712c10cfa582e9c3/resources/assets/css/fonts/element-icons.ttf
--------------------------------------------------------------------------------
/resources/assets/css/fonts/element-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/foryoufeng/laravel-generator/96a960d660ad8bf6f0955746712c10cfa582e9c3/resources/assets/css/fonts/element-icons.woff
--------------------------------------------------------------------------------
/resources/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/foryoufeng/laravel-generator/96a960d660ad8bf6f0955746712c10cfa582e9c3/resources/assets/images/logo.png
--------------------------------------------------------------------------------
/resources/assets/js/axios.js:
--------------------------------------------------------------------------------
1 | /* axios v0.18.0 | (c) 2018 by Matt Zabriskie */
2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new s(e),n=i(s.prototype.request,t);return o.extend(n,s.prototype,t),o.extend(n,t),n}var o=n(2),i=n(3),s=n(5),u=n(6),a=r(u);a.Axios=s,a.create=function(e){return r(o.merge(u,e))},a.Cancel=n(23),a.CancelToken=n(24),a.isCancel=n(20),a.all=function(e){return Promise.all(e)},a.spread=n(25),e.exports=a,e.exports.default=a},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"[object ArrayBuffer]"===R.call(e)}function i(e){return"undefined"!=typeof FormData&&e instanceof FormData}function s(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function u(e){return"string"==typeof e}function a(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===R.call(e)}function d(e){return"[object File]"===R.call(e)}function l(e){return"[object Blob]"===R.call(e)}function h(e){return"[object Function]"===R.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function w(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function g(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n
6 | * @license MIT
7 | */
8 | e.exports=function(e){return null!=e&&(n(e)||r(e)||!!e._isBuffer)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new s,response:new s}}var o=n(6),i=n(2),s=n(17),u=n(18);r.prototype.request=function(e){"string"==typeof e&&(e=i.merge({url:arguments[0]},arguments[1])),e=i.merge(o,{method:"get"},this.defaults,e),e.method=e.method.toLowerCase();var t=[u,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},i.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(i.merge(n||{},{method:e,url:t}))}}),i.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(i.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e,t){!i.isUndefined(e)&&i.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof XMLHttpRequest?e=n(8):"undefined"!=typeof process&&(e=n(8)),e}var i=n(2),s=n(7),u={"Content-Type":"application/x-www-form-urlencoded"},a={adapter:o(),transformRequest:[function(e,t){return s(t,"Content-Type"),i.isFormData(e)||i.isArrayBuffer(e)||i.isBuffer(e)||i.isStream(e)||i.isFile(e)||i.isBlob(e)?e:i.isArrayBufferView(e)?e.buffer:i.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):i.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};a.headers={common:{Accept:"application/json, text/plain, */*"}},i.forEach(["delete","get","head"],function(e){a.headers[e]={}}),i.forEach(["post","put","patch"],function(e){a.headers[e]=i.merge(u)}),e.exports=a},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(9),i=n(12),s=n(13),u=n(14),a=n(10),c="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||n(15);e.exports=function(e){return new Promise(function(t,f){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest,h="onreadystatechange",m=!1;if("undefined"==typeof window||!window.XDomainRequest||"withCredentials"in l||u(e.url)||(l=new window.XDomainRequest,h="onload",m=!0,l.onprogress=function(){},l.ontimeout=function(){}),e.auth){var y=e.auth.username||"",w=e.auth.password||"";d.Authorization="Basic "+c(y+":"+w)}if(l.open(e.method.toUpperCase(),i(e.url,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l[h]=function(){if(l&&(4===l.readyState||m)&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in l?s(l.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?l.response:l.responseText,i={data:r,status:1223===l.status?204:l.status,statusText:1223===l.status?"No Content":l.statusText,headers:n,config:e,request:l};o(t,f,i),l=null}},l.onerror=function(){f(a("Network Error",e,null,l)),l=null},l.ontimeout=function(){f(a("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",l)),l=null},r.isStandardBrowserEnv()){var g=n(16),v=(e.withCredentials||u(e.url))&&e.xsrfCookieName?g.read(e.xsrfCookieName):void 0;v&&(d[e.xsrfHeaderName]=v)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),e.withCredentials&&(l.withCredentials=!0),e.responseType)try{l.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),f(e),l=null)}),void 0===p&&(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(10);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";var r=n(11);e.exports=function(e,t,n,o,i){var s=new Error(e);return r(s,t,n,o,i)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var i;if(n)i=n(t);else if(o.isURLSearchParams(t))i=t.toString();else{var s=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),s.push(r(t)+"="+r(e))}))}),i=s.join("&")}return i&&(e+=(e.indexOf("?")===-1?"?":"&")+i),e}},function(e,t,n){"use strict";var r=n(2),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,s={};return e?(r.forEach(e.split("\n"),function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(s[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?s[t]=(s[t]?s[t]:[]).concat([n]):s[t]=s[t]?s[t]+", "+n:n}}),s):s}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t){"use strict";function n(){this.message="String contains an invalid character"}function r(e){for(var t,r,i=String(e),s="",u=0,a=o;i.charAt(0|u)||(a="=",u%1);s+=a.charAt(63&t>>8-u%1*8)){if(r=i.charCodeAt(u+=.75),r>255)throw new n;t=t<<8|r}return s}var o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.prototype=new Error,n.prototype.code=5,n.prototype.name="InvalidCharacterError",e.exports=r},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,i,s){var u=[];u.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&u.push("expires="+new Date(n).toGMTString()),r.isString(o)&&u.push("path="+o),r.isString(i)&&u.push("domain="+i),s===!0&&u.push("secure"),document.cookie=u.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),i=n(19),s=n(20),u=n(6),a=n(21),c=n(22);e.exports=function(e){r(e),e.baseURL&&!a(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=i(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||u.adapter;return t(e).then(function(t){return r(e),t.data=i(t.data,t.headers,e.transformResponse),t},function(t){return s(t)||(r(e),t&&t.response&&(t.response.data=i(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])});
9 | //# sourceMappingURL=axios.min.map
--------------------------------------------------------------------------------
/resources/assets/vs/basic-languages/java/java.js:
--------------------------------------------------------------------------------
1 | /*!-----------------------------------------------------------------------------
2 | * Copyright (c) Microsoft Corporation. All rights reserved.
3 | * monaco-languages version: 1.6.0(858705e74270e53559a241fdee187e7a6ae53b23)
4 | * Released under the MIT license
5 | * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
6 | *-----------------------------------------------------------------------------*/
7 | define("vs/basic-languages/java/java",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}],folding:{markers:{start:new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:))")}}},t.language={defaultToken:"",tokenPostfix:".java",keywords:["abstract","continue","for","new","switch","assert","default","goto","package","synchronized","boolean","do","if","private","this","break","double","implements","protected","throw","byte","else","import","public","throws","case","enum","instanceof","return","transient","catch","extends","int","short","try","char","final","interface","static","void","class","finally","long","strictfp","volatile","const","float","native","super","while","true","false"],operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,"annotation"],[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/,"number.float"],[/0[xX](@hexdigits)[Ll]?/,"number.hex"],[/0(@octaldigits)[Ll]?/,"number.octal"],[/0[bB](@binarydigits)[Ll]?/,"number.binary"],[/(@digits)[fFdD]/,"number.float"],[/(@digits)[lL]?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@javadoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],javadoc:[[/[^\/*]+/,"comment.doc"],[/\/\*/,"comment.doc.invalid"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]]}}});
--------------------------------------------------------------------------------
/resources/assets/vs/language/css/cssMode.js:
--------------------------------------------------------------------------------
1 | /*!-----------------------------------------------------------------------------
2 | * Copyright (c) Microsoft Corporation. All rights reserved.
3 | * monaco-css version: 2.3.0(a450f6054cbfb890c2ede882f6d2e47cc0e47f2f)
4 | * Released under the MIT license
5 | * https://github.com/Microsoft/monaco-css/blob/master/LICENSE.md
6 | *-----------------------------------------------------------------------------*/
7 | define("vs/language/css/workerManager",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var t=function(){function e(e){var n=this;this._defaults=e,this._worker=null,this._idleCheckInterval=setInterval(function(){return n._checkIfIdle()},3e4),this._lastUsedTime=0,this._configChangeListener=this._defaults.onDidChange(function(){return n._stopWorker()})}return e.prototype._stopWorker=function(){this._worker&&(this._worker.dispose(),this._worker=null),this._client=null},e.prototype.dispose=function(){clearInterval(this._idleCheckInterval),this._configChangeListener.dispose(),this._stopWorker()},e.prototype._checkIfIdle=function(){this._worker&&(12e4e?r=i:t=i+1}var o=t-1;return a.create(o,e-n[o])},e.prototype.offsetAt=function(e){var n=this.getLineOffsets();if(e.line>=n.length)return this._content.length;if(e.line<0)return 0;var t=n[e.line],r=e.line+1e?r=i:n=i+1}var o=n-1;return a.create(o,e-t[o])},e.prototype.offsetAt=function(e){var t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;var n=t[e.line],r=e.line+1'Migrate',
10 | 'generator'=>'Generator',
11 | 'creator'=>'Creator',
12 | 'modelName'=>'Model Name',
13 | 'generateLog'=>'Generate Logs',
14 | 'displayName'=>'Display Name',
15 | 'modelDisplayNameDesc'=>'The actual name of the model, such as User',
16 | 'fieldName'=>'the field in table',
17 | 'displayNameDesc'=>'The name actually displayed such as goods name',
18 | 'youNeed'=>'if you need',
19 | 'soAttach'=>'attach can be 5,2',
20 | 'templates'=>'templates',
21 | 'optional'=>'optional',
22 | 'noData'=>'no data',
23 | 'showLists'=>'ShowList',
24 | 'showListsDesc'=>'Show this field in the table lists',
25 | 'canSearch'=>'Search',
26 | 'canSearchDesc'=>'this field can search in the table lists',
27 | 'templateName'=>'name',
28 | 'templatePath'=>'path',
29 | 'templateFileName'=>'file_name',
30 | 'templateIsChecked'=>'is_checked',
31 | 'group'=>'Group',
32 | 'yes'=>'yes',
33 | 'sure'=>'Sure',
34 | 'cancel'=>'Cancel',
35 | 'notice'=>'Notice',
36 | 'no'=>'no',
37 | 'delete'=>'delete',
38 | 'edit'=>'edit',
39 | 'copy'=>'Copy',
40 | 'defaultValue'=>'Default Value',
41 | 'notFound'=>'not found',
42 | 'actions'=>'actions',
43 | 'add'=>'Add',
44 | 'rule'=>'Rule',
45 | 'action'=>'Action',
46 | 'foreign'=>'Foreign',
47 | 'relationship'=>'Relationships',
48 | 'relationshipDesc'=>'Available relationship fields',
49 | 'error'=>'error',
50 | 'success'=>'success',
51 | 'deleteSuccess'=>'Successfully deleted',
52 | 'deleteFailed'=>'Failed to delete',
53 | 'confirmDelete'=>'Confirm to delete ?',
54 | 'modelNotDelete'=>'Model is not allowed to delete',
55 | 'name'=>'name',
56 | 'addTime'=>'Add Time',
57 | 'updateTime'=>'Update Time',
58 | 'currentTime'=>'Current Time',
59 | 'file'=>'file',
60 | 'submitError'=>'submit error',
61 | 'submitSuccess'=>'submit success',
62 | 'namespace'=>'namespace',
63 | 'template'=>'template',
64 | 'total'=>'Total',
65 | 'line'=>' ',
66 | 'tableInfo'=>'Table Info',
67 | 'tableFields'=>'Table Fields',
68 | 'required'=>'is required',
69 | 'ifNotExit'=>'can add if not exist ',
70 | 'hasExists'=>'already exists',
71 | 'submit'=>'Submit',
72 | 'save'=>'Save',
73 | 'saveGenerate'=>'Save&&Generate',
74 | 'classInfo'=>'Class Info',
75 | 'className'=>'Class',
76 | 'classDisplayName'=>'Display Name',
77 | 'camelClassName'=>'Camel Class',
78 | 'SnakeClassName'=>'Snake Class',
79 | 'PluralClassName'=>'Plural Class',
80 | 'SnakePluralClassName'=>'Snake Plural Class',
81 | 'classNameDesc'=>'will be replaced to the real class name',
82 | 'classDisplayNameDesc'=>'will be replaced to the actual name of the model, which is mean to the modelDisplayName',
83 | 'camelClassNameDesc'=>'will be replaced to camel_case such as laravelGenerator',
84 | 'SnakeClassNameDesc'=>'will be replaced to snake_case such as laravel_generator',
85 | 'PluralClassNameDesc'=>'will be replaced to its plural form,currently only supports the English language such as LaravelGenerators',
86 | 'SnakePluralClassNameDesc'=>'will be replaced to snake and then to its plural form such as laravel_generators',
87 | 'template_not_empty' => "The template cannot be empty",
88 | 'exist_table' => 'Table already exists',
89 | 'select' => 'Please select',
90 | ];
91 |
--------------------------------------------------------------------------------
/resources/lang/zh_CN/generator.php:
--------------------------------------------------------------------------------
1 | '迁移',
10 | 'generator'=>'生成器',
11 | 'creator'=>'创建人',
12 | 'modelName'=>'Model名称',
13 | 'generateLog'=>'生成记录',
14 | 'displayName'=>'显示名称',
15 | 'modelDisplayNameDesc'=>'模型的实际名称,如用户',
16 | 'fieldName'=>'表里的字段名',
17 | 'displayNameDesc'=>'列表中实际显示的名称,如商品名称',
18 | 'youNeed'=>'如果你需要',
19 | 'soAttach'=>'那么attach可以填入5,2',
20 | 'templates'=>'模板',
21 | 'optional'=>'可选的',
22 | 'noData'=>'没有数据',
23 | 'showLists'=>'列表显示',
24 | 'showListsDesc'=>'该字段在列表页显示',
25 | 'canSearch'=>'搜索',
26 | 'canSearchDesc'=>'该字段在列表页是可搜索的',
27 | 'templateName'=>'名称',
28 | 'templatePath'=>'路径',
29 | 'templateFileName'=>'文件名',
30 | 'templateIsChecked'=>'是否选中',
31 | 'group'=>'所属组',
32 | 'yes'=>'是',
33 | 'sure'=>'确定',
34 | 'cancel'=>'取消',
35 | 'notice'=>'提示',
36 | 'no'=>'否',
37 | 'delete'=>'删除',
38 | 'edit'=>'编辑',
39 | 'copy'=>'复制',
40 | 'notFound'=>'没有找到',
41 | 'defaultValue'=>'默认值',
42 | 'actions'=>'操作',
43 | 'add'=>'添加',
44 | 'rule'=>'规则',
45 | 'action'=>'操作',
46 | 'foreign'=>'外键',
47 | 'relationship'=>'关联关系',
48 | 'relationshipDesc'=>'可使用的关联关系字段',
49 | 'error'=>'错误',
50 | 'success'=>'成功',
51 | 'deleteSuccess'=>'删除成功',
52 | 'deleteFailed'=>'删除失败',
53 | 'confirmDelete'=>'确认删除吗?',
54 | 'modelNotDelete'=>'model 是不允许删除的',
55 | 'name'=>'名称',
56 | 'addTime'=>'添加时间',
57 | 'updateTime'=>'更新时间',
58 | 'currentTime'=>'当前时间',
59 | 'file'=>'文件',
60 | 'submitError'=>'提交失败',
61 | 'submitSuccess'=>'提交成功',
62 | 'namespace'=>'命名空间',
63 | 'template'=>'模板',
64 | 'total'=>'共',
65 | 'line'=>'条',
66 | 'tableInfo'=>'表信息',
67 | 'tableFields'=>'表字段',
68 | 'required'=>'是必须的',
69 | 'ifNotExit'=>'如果不存着可以添加 ',
70 | 'hasExists'=>'已经存在',
71 | 'submit'=>'提交',
72 | 'save'=>'保存',
73 | 'saveGenerate'=>'保存并生成',
74 | 'classInfo'=>'类信息',
75 | 'className'=>'类',
76 | 'classDisplayName'=>'显示名称',
77 | 'camelClassName'=>'类驼峰',
78 | 'SnakeClassName'=>'类小写',
79 | 'PluralClassName'=>'类复数',
80 | 'SnakePluralClassName'=>'类小写复数',
81 | 'classNameDesc'=>'将被替换为类的实际名称',
82 | 'classDisplayNameDesc'=>'将被替换为类的实际名称,对应填入的modelDisplayName的值',
83 | 'camelClassNameDesc'=>'将被替换为类的驼峰形式 如laravelGenerator',
84 | 'SnakeClassNameDesc'=>'将被替换为类的小写形式 如laravel_generator',
85 | 'PluralClassNameDesc'=>'将被替换为类的复数形式 如LaravelGenerators',
86 | 'SnakePluralClassNameDesc'=>'将被替换为类的小写复数形式 如laravel_generators',
87 | 'template_not_empty' => "模板不能为空",
88 | 'exist_table'=>'已存在表',
89 | 'select'=>'请选择',
90 | ];
91 |
--------------------------------------------------------------------------------
/resources/migrations/2025_04_11_095115_create_laravel_generators_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
16 | $table->string('name')->unique()->comment('模板组');
17 | $table->timestamps();
18 | });
19 |
20 | Schema::create('laravel_generators', function (Blueprint $table) {
21 | $table->increments('id');
22 | $table->string('name')->comment('名称');
23 | $table->string('path')->comment('保存路径');
24 | $table->string('file_name')->comment('文件名');
25 | $table->char('is_checked', 1)->comment('是否选中 0 不选中 1 选中');
26 | $table->text('template')->coment('模板');
27 | $table->unsignedInteger('template_id');
28 | $table->foreign('template_id')->references('id')->on('laravel_generator_types');
29 |
30 | $table->timestamps();
31 | });
32 |
33 | Schema::create('laravel_generator_logs', function (Blueprint $table) {
34 | $table->increments('id');
35 | $table->string('model_name')->comment('model name');
36 | $table->string('display_name')->comment('display name');
37 | $table->string('creator')->comment('creator');
38 | $table->json('configs')->comment('configs');
39 | $table->timestamps();
40 | });
41 |
42 | Schema::create('laravel_generator_configs', function (Blueprint $table) {
43 | $table->increments('id');
44 | $table->string('group')->comment('group');
45 | $table->string('alias')->unique()->comment('alias');
46 | $table->text('config')->comment('config');
47 | $table->timestamps();
48 | });
49 | }
50 |
51 | /**
52 | * Reverse the migrations.
53 | */
54 | public function down()
55 | {
56 | Schema::dropIfExists('laravel_generators');
57 | Schema::dropIfExists('laravel_generator_types');
58 | Schema::dropIfExists('laravel_generator_logs');
59 | Schema::dropIfExists('laravel_generator_configs');
60 | }
61 | };
62 |
--------------------------------------------------------------------------------
/resources/views/generator.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @lang('laravel-generator::generator.generator')
3 |
4 |
5 |
6 |
7 |
8 |
9 | @lang('laravel-generator::generator.modelDisplayNameDesc')
10 |
11 |
12 |
13 |
14 |
15 |
16 | Create migration
17 | Run migrate
18 | ide-helper:models
19 |
20 |
21 | {{-- 模板的数据 --}}
22 |
23 |
24 |
25 |
26 |
27 | {{-- 表字段/start --}}
28 |
29 |
30 |
31 |
32 | @lang('laravel-generator::generator.fieldName')
33 | Field name
34 |
35 |
36 |
37 |
38 | @lang('laravel-generator::generator.displayNameDesc')
39 | @lang('laravel-generator::generator.displayName')
40 |
41 |
42 | Type
43 |
44 |
45 | @lang('laravel-generator::generator.youNeed')$table->decimal('amount', 5, 2),@lang('laravel-generator::generator.soAttach')
46 | attach
47 |
48 |
49 | Nullable
50 | Key
51 | Default Value
52 | Comment
53 |
54 |
55 | @lang('laravel-generator::generator.showListsDesc')
56 | @lang('laravel-generator::generator.showLists')
57 |
58 |
59 |
60 |
61 | @lang('laravel-generator::generator.canSearchDesc')
62 | @lang('laravel-generator::generator.canSearch')
63 |
64 |
65 | @lang('laravel-generator::generator.rule')
66 | @lang('laravel-generator::generator.action')
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
118 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Add field
131 |
135 |
136 |
140 |
141 |
142 | {{-- 表字段/end --}}
143 |
144 | {{-- 添加外键关系/start --}}
145 |
146 | @lang('laravel-generator::generator.add') @lang('laravel-generator::generator.foreign')
147 |
148 |
149 |
150 |
151 | foreign
152 |
153 |
154 | references
155 |
156 | on
157 |
158 | onDelete
159 |
160 |
161 | onUpdate
162 |
163 | Action
164 |
165 |
166 |
167 |
169 |
176 |
177 |
178 |
179 |
180 |
182 |
187 |
188 |
189 |
190 |
191 |
194 |
199 |
200 |
201 |
202 |
203 |
204 |
209 |
210 |
211 |
212 |
213 |
214 |
219 |
220 |
221 |
222 |
223 |
224 |
225 | {{-- 添加外键关系/end --}}
226 |
227 | {{-- 添加关联关系/start --}}
228 |
229 | @lang('laravel-generator::generator.add') @lang('laravel-generator::generator.relationship')
230 |
231 |
232 |
233 | relationship
234 |
235 | RelationModel
236 |
237 |
238 | foreign_key
239 |
240 |
241 | Reverse
242 |
243 |
244 | With
245 |
246 |
247 | Search
248 |
249 | Action
250 |
251 |
252 |
253 |
255 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
273 |
278 |
279 |
280 |
281 |
282 | with
283 |
284 |
285 | search
286 |
287 |
288 |
289 | @{{ relationship.relation }}
290 | @{{ relationship.reverseRelation }}
291 |
292 |
293 |
294 | {{-- 添加关联关系/end --}}
295 |
296 |
297 | @lang('laravel-generator::generator.save')
298 | @lang('laravel-generator::generator.saveGenerate')
299 |
300 |
301 |
302 |
303 |
--------------------------------------------------------------------------------
/resources/views/generator_logs.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @lang('laravel-generator::generator.generateLog')
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ trans('laravel-generator::generator.add') }}
19 | {{ trans('laravel-generator::generator.exist_table') }}
20 |
30 |
35 |
36 |
37 |
38 |
39 |
44 |
48 |
49 |
52 |
53 | @{{ scope.row.model_name }}
54 |
55 |
56 |
60 |
61 |
64 |
65 |
68 |
69 |
72 |
73 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | @lang('laravel-generator::generator.total') @{{ pageInfo.total }} @lang('laravel-generator::generator.line')
94 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | @lang('laravel-generator::generator.modelName'):
107 | @{{ logRow.modelName }}
108 | @lang('laravel-generator::generator.displayName'): @{{ logRow.modelDisplayName }}
109 |
110 |
111 |
112 |
113 | Create migration
114 | Run migrate
115 | ide-helper:models
116 |
117 |
118 |
119 |
Table fileds
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
151 |
152 |
156 |
157 |
158 |
159 | {{-- --}}
160 | {{--
@lang('laravel-generator::generator.foreign')
--}}
161 | {{-- --}}
162 |
163 |
--------------------------------------------------------------------------------
/resources/views/generator_migrate.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @lang('laravel-generator::generator.migrate')
3 |
4 |
5 |
6 |
7 |
8 | @{{migrateName}}
9 |
10 |
11 |
12 | Run migrate
13 |
14 |
15 |
16 |
17 | Field name
18 |
19 | Type
20 |
21 |
22 | @lang('laravel-generator::generator.youNeed')$table->decimal('amount', 5, 2),@lang('laravel-generator::generator.soAttach')
23 | attach
24 |
25 |
26 | Nullable
27 | Key
28 | Default value
29 | Comment
30 | Change
31 | Action
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | Add field
79 |
80 |
81 |
82 | submit
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/resources/views/layout.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{config('laravel-generator.name','Laravel Generator')}}
11 |
12 |
13 |
14 |
55 |
56 |
57 |
58 |
59 |
60 |
85 |
86 | @yield('content')
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
148 | @yield('js')
149 | @yield('css')
150 |
151 |
152 |
--------------------------------------------------------------------------------
/resources/views/template_lists.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {{ trans('laravel-generator::generator.templates') }}
3 |
4 |
5 |
6 |
7 |
11 |
16 |
17 |
18 |
19 |
20 | {{ trans('laravel-generator::generator.add') }}
21 |
22 |
23 |
24 |
28 |
32 |
33 |
37 |
38 |
41 |
42 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/routes/route.php:
--------------------------------------------------------------------------------
1 | group(function () {
9 | Route::get('{locale?}', [GeneratorController::class, 'index'])->name('generator.index')->where('locale', 'en|zh_CN');
10 | Route::get('model/{name?}', [GeneratorController::class, 'dummyValues'])->name('generator.dummyValues');
11 | Route::get('table/{table_name?}', [GeneratorController::class, 'createByTable'])->name('generator.create_by_table');
12 | Route::post('/', [GeneratorController::class, 'store'])->name('generator.store');
13 | Route::post('migrate', [GeneratorController::class, 'migrate'])->name('generator.migrate');
14 | Route::get('template', [GeneratorTemplateController::class, 'index'])->name('generator.template.index');
15 | Route::get('template/update/{locale?}', [GeneratorTemplateController::class, 'update'])->name('generator.template.update');
16 | Route::post('template/save', [GeneratorTemplateController::class, 'save'])->name('generator.template.save');
17 | Route::post('template/delete', [GeneratorTemplateController::class, 'delete'])->name('generator.template.delete');
18 | Route::post('template/compile', [GeneratorTemplateController::class, 'compile'])->name('generator.template.compile');
19 | Route::post('template/updateType', [GeneratorTemplateController::class, 'updateType'])->name('generator.template.updateType');
20 | Route::get('logs', [GeneratorController::class, 'getLogs'])->name('generator.logs');
21 | Route::post('log/delete', [GeneratorController::class, 'deleteLog'])->name('generator.deleteLog');
22 | Route::get('assets/{path}', AssetController::class)->where('path', '.*');
23 | });
24 |
25 |
--------------------------------------------------------------------------------
/src/Console/InstallCommand.php:
--------------------------------------------------------------------------------
1 | call('migrate');
33 | //add default seeds
34 | $this->call('db:seed', ['--class' => GeneratorSeeder::class]);
35 | $this->info('Generator installed successfully.');
36 | $host = config('app.url');
37 | $this->info('🌐 access url: ' . route('generator.index'));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Controllers/AssetController.php:
--------------------------------------------------------------------------------
1 | 'text/css',
27 | 'js' => 'application/javascript',
28 | 'woff2' => 'font/woff2',
29 | 'woff' => 'font/woff',
30 | 'ttf' => 'font/ttf',
31 | 'svg' => 'image/svg+xml',
32 | 'png' => 'image/png',
33 | 'jpg' => 'image/jpeg',
34 | 'jpeg' => 'image/jpeg',
35 | 'gif' => 'image/gif',
36 | ];
37 |
38 | $mime = $mimeTypes[$extension] ?? 'application/octet-stream';
39 |
40 | return Response::make(File::get($fullPath), 200, [
41 | 'Content-Type' => $mime,
42 | ]);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Controllers/GeneratorController.php:
--------------------------------------------------------------------------------
1 | get('tab', 'log');
45 | // 获取所有的表
46 | $tables = GeneratorUtils::getTables();
47 | // 获取可用的数据类型
48 | $dbTypes = GeneratorUtils::getDbTypes();
49 | // 获取模板列表
50 | $template_types = $this->getTemplateTypes();
51 | // 获取模型的信息
52 | $modelInfo = $this->getModelInfo();
53 | // 获取可用的规则
54 | $rules = $this->getRules();
55 | // 可用的假属性字段
56 | $dummyAttrs = GeneratorUtils::getDummyAttrs();
57 | // 自定义变量
58 | $customDummys = config('laravel-generator.customDummys');
59 | $language_value = $locale === 'en' ? 'English' : '简体中文';
60 |
61 | return view('laravel-generator::index', compact('dbTypes', 'generator', 'language_value', 'locale',
62 | 'tab', 'template_types', 'dummyAttrs', 'tables', 'rules', 'modelInfo', 'customDummys'));
63 | }
64 |
65 | /**
66 | * 获取指定的名称的转换数据.
67 | *
68 | *
69 | * @return \Illuminate\Http\JsonResponse
70 | */
71 | public function dummyValues($name)
72 | {
73 | if ($name) {
74 | return $this->success(GeneratorUtils::getDummyValues($name));
75 | }
76 |
77 | return $this->error(trans('generator.error'));
78 | }
79 |
80 | /**
81 | * save data.
82 | *
83 | *
84 | * @return \Illuminate\Http\JsonResponse
85 | */
86 | public function store(Request $request)
87 | {
88 | $paths = [];
89 | $data = $request->validate([
90 | 'id' => 'required',
91 | 'modelName' => 'required',
92 | 'primary_key' => 'required',
93 | 'soft_deletes' => 'required',
94 | 'timestamps' => 'required',
95 | 'modelDisplayName' => 'required',
96 | 'submit_type' => 'required',
97 | 'relationships' => 'array',
98 | 'table_fields' => 'array',
99 | 'generator_templates' => 'array',
100 | ]);
101 | $model_name = $data['modelName'];
102 | $log = LaravelGeneratorLog::firstOrNew([
103 | 'model_name' => $model_name,
104 | ]);
105 | $item['model_name'] = $model_name;
106 | $item['display_name'] = $data['modelDisplayName'];
107 | $item['creator'] = config('laravel-generator.custom_keys.author', '');
108 | $item['configs'] = json_encode($request->except('id'));
109 | $log->fill($item);
110 | $res = $log->save();
111 | if ($data['submit_type'] === 'save') {
112 | if ($res) {
113 | return $this->success(['save success']);
114 | }
115 |
116 | return $this->error('save error');
117 | }
118 | // 获取模型的信息
119 | $modelInfo = $this->getModelInfo();
120 | try {
121 | $table_fields = $request->get('table_fields');
122 | // 生成数据
123 | $model_name = $data['modelName'];
124 |
125 | $create = $request->get('create', []);
126 | // 1. 是否运行 Create migration.
127 | if (\in_array('migration', $create, true)) {
128 | $table_name = Str::plural(Str::snake(class_basename($model_name)));
129 | $migrationName = 'create_'.$table_name.'_table';
130 |
131 | $paths['migration'] = (new MigrationCreator(app('files'), database_path('migrations')))->buildBluePrint(
132 | $table_fields,
133 | 'id',
134 | $request->get('timestamps'),
135 | $request->get('soft_deletes'),
136 | $request->get('foreigns')
137 | )->create($migrationName, database_path('migrations'), $table_name);
138 | }
139 | // 2. 是否运行Run migrate.
140 | if (\in_array('migrate', $create, true)) {
141 | Artisan::call('migrate');
142 | $message = Artisan::output();
143 | $paths['migrate'] = $message;
144 | }
145 | // 4.生成模板文件
146 | $generator_templates = $data['generator_templates'];
147 | $file = app('files');
148 |
149 | foreach ($generator_templates as $k => $template) {
150 | $file_real_name = $template['file_real_name'];
151 | $content = GeneratorUtils::compile($template['template'],$data);
152 | $path = base_path($file_real_name);
153 | if ($file->exists($path)) {
154 | // route special handling
155 | if (str_contains($file_real_name, 'routes/') && str_contains($file_real_name, '.php')) {
156 | $file->append($path, str_replace('create();
163 | }
164 | }
165 | // 5.处理关联关系
166 | $relationships = $request->get('relationships');
167 | $this->dealRelationShips($relationships, $model_name, $modelInfo);
168 | // 6.是否运行idea代码提示
169 | if (\in_array('ide-helper', $create, true)) {
170 | Artisan::call('ide-helper:models', [
171 | '--write' => true,
172 | '--write-eloquent-helper' => true,
173 | 'model' => [
174 | ucfirst(str_replace('/', '\\', $modelInfo->path).$model_name),
175 | ],
176 | ]);
177 | }
178 | } catch (\Exception $exception) {
179 | return $this->error($exception->getFile().'-'.$exception->getLine().':'.$exception->getMessage());
180 | }
181 |
182 | return $this->success($paths);
183 | }
184 |
185 | public function migrate(Request $request)
186 | {
187 | $doMigrate = $request->get('doMigrate', []);
188 | $table_fields = $request->get('table_fields');
189 | try {
190 | // 新增加迁移文件
191 | if (\in_array('migration', $doMigrate, true)) {
192 | $tableName = $request->get('tableName');
193 | $migrationName = $request->get('prefix').'_';
194 | if (count($table_fields) > 2) {
195 | $migrationName .= $table_fields[0]['field_name'].'AndMore';
196 | } else {
197 | $migrationName .= collect($table_fields)->pluck('field_name')->implode('_');
198 | }
199 | $migrationName .= '_'.$tableName.'_table';
200 | $paths['migration'] = (new MigrationCreator(app('files'), database_path('migrations')))->buildBluePrint($table_fields, null, false)
201 | ->create($migrationName, database_path('migrations'), $tableName, false);
202 | // Run migrate.
203 | if (\in_array('migrate', $request->get('doMigrate'), true)) {
204 | Artisan::call('migrate');
205 | $message = Artisan::output();
206 | $paths['migrate'] = $message;
207 | }
208 | }
209 | } catch (\Exception $exception) {
210 | return $this->error($exception->getFile().'-'.$exception->getLine().':'.$exception->getMessage());
211 | }
212 |
213 | return $this->success($paths);
214 | }
215 | private function dealRelationShips($relationships, $model_name, $modelInfo)
216 | {
217 | if ($relationships) {
218 | foreach ($relationships as $relationship) {
219 | // 替换相对模型的数据
220 | $file_name = base_path($modelInfo->path).$relationship['model'].'.php';
221 | if ($relationship['reverse'] && file_exists($file_name)) {
222 | $oldData = file_get_contents($file_name);
223 | $oldData = str_replace(["\n\n\n", "\n \n"], ["\n\n", ''], substr($oldData, 0, -1));
224 | $oldData = substr($oldData, 0, -1);
225 | if ($relationship['reverse'] === 'hasMany') {
226 | $funName = Str::snake(Str::plural($model_name));
227 | } else {
228 | $funName = Str::camel($model_name);
229 | }
230 | $key = '';
231 | if ($relationship['foreign_key']) {
232 | $key = ",'{$relationship['foreign_key']}'";
233 | }
234 | $oldData .= " public function {$funName}(){\n";
235 | $oldData .= " return \$this->{$relationship['reverse']}({$model_name}::class{$key});\n";
236 | $oldData .= " }\n\n}";
237 | file_put_contents($file_name, $oldData);
238 | }
239 | }
240 | }
241 |
242 | return true;
243 | }
244 |
245 | /**
246 | * 获取可用的规则.
247 | *
248 | * @return array
249 | */
250 | private function getRules()
251 | {
252 | $rules = [];
253 | $configRules = config('laravel-generator.rules');
254 | foreach ($configRules as $k => $rule) {
255 | $rules[$k]['label'] = $rule;
256 | $rules[$k]['value'] = $rule;
257 | }
258 |
259 | return $rules;
260 | }
261 |
262 | /**
263 | * 获取模型的信息.
264 | *
265 | * @return mixed
266 | */
267 | private function getModelInfo()
268 | {
269 | $model = LaravelGenerator::whereHas('template_type', function ($query) {
270 | $query->whereName(LaravelGeneratorType::MODEL);
271 | })->first();
272 | if (! $model) {
273 | throw new \RuntimeException('the template model not found');
274 | }
275 |
276 | return $model;
277 | }
278 |
279 | /**
280 | * get the all template types.
281 | *
282 | * @return LaravelGeneratorType[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection
283 | */
284 | private function getTemplateTypes()
285 | {
286 | $data = LaravelGeneratorType::with('templates')->get();
287 | $select = $data->map(function ($item) {
288 | $data = [];
289 | $data['label'] = $item->name;
290 | $data['value'] = $item->id;
291 |
292 | return $data;
293 | });
294 | $data = $data->map(function ($item) {
295 | $item->checked = $item->templates->filter(function ($value) {
296 | return $value['is_checked'];
297 | })->pluck('id');
298 | $item->templates = $item->templates->map(function ($temp) {
299 | $temp->file_real_name = $temp->path.$temp->file_name;
300 |
301 | return $temp;
302 | });
303 |
304 | return $item;
305 | });
306 |
307 | return [
308 | 'datas' => $data,
309 | 'select' => $select,
310 | ];
311 | }
312 |
313 | public function getLogs(Request $request)
314 | {
315 | $model_name = $request->get('model_name');
316 | $display_name = $request->get('display_name');
317 | $creator = $request->get('creator');
318 |
319 | $datas = LaravelGeneratorLog::when($model_name, fn ($query) => $query->where('model_name', 'like', '%'.$model_name.'%'))
320 | ->when($display_name, fn ($query) => $query->where('display_name', 'like', '%'.$display_name.'%'))
321 | ->when($creator, fn ($query) => $query->where('creator', 'like', '%'.$creator.'%'))
322 | ->orderBy('id', 'desc')
323 | ->paginate();
324 |
325 | return $this->success($datas);
326 | }
327 |
328 | public function deleteLog(Request $request)
329 | {
330 | $id = $request->get('id');
331 |
332 | $res = LaravelGeneratorLog::whereId($id)->delete();
333 |
334 | if ($res) {
335 | return $this->success('success');
336 | }
337 |
338 | return $this->error('delete error');
339 | }
340 |
341 | public function createByTable(string $table_name)
342 | {
343 | if (!$table_name) {
344 | return $this->error('table_name is required');
345 | }
346 | try {
347 | $table_columns = GeneratorUtils::tableToForm($table_name);
348 |
349 | return $this->success($table_columns);
350 |
351 | }catch (Exception $exception){
352 | return $this->error($exception->getMessage());
353 | }
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/src/Controllers/GeneratorTemplateController.php:
--------------------------------------------------------------------------------
1 | get('name');
39 | $template_id = $request->get('template_id');
40 | $query = LaravelGenerator::with('template_type');
41 | if ($name) {
42 | $query = $query->where('name', 'like', '%'.$name.'%');
43 | }
44 | if ($template_id) {
45 | $query = $query->where('template_id', $template_id);
46 | }
47 |
48 | return $this->success($query->get());
49 | }
50 |
51 | /**
52 | * 更新操作.
53 | *
54 | *
55 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
56 | */
57 | public function update(Request $request, ?string $locale = null)
58 | {
59 | $locale = $locale ?? config('app.locale', 'en');
60 | if (! in_array($locale, ['en', 'zh_CN'])) {
61 | $locale = 'en';
62 | }
63 | App::setLocale($locale);
64 | // do ajax request
65 | $id = (int) $request->get('id');
66 | // 表单数据
67 | $form = $this->getForm($id);
68 | // 获取模板组列表
69 | $template_types = $this->getTemplateTypes();
70 | // 提供的演示数据
71 | $laravel_generators = GeneratorUtils::getGenerators();
72 | // 可用的假属性字段
73 | $dummyAttrs = GeneratorUtils::getDummyAttrs();
74 | // 可用的函数
75 | $functions = GeneratorUtils::getFunctions();
76 | // 自定义变量
77 | $customKeys = GeneratorUtils::getCustomKeys();
78 | $tags = GeneratorUtils::getTags();
79 | $language_value = $locale === 'en' ? 'English' : '简体中文';
80 |
81 | return view('laravel-generator::template_update', compact('template_types', 'tags', 'locale', 'language_value',
82 | 'laravel_generators', 'dummyAttrs', 'functions', 'form', 'customKeys'));
83 | }
84 |
85 | /**
86 | * 删除操作.
87 | *
88 | *
89 | * @return \Illuminate\Http\JsonResponse
90 | */
91 | public function delete(Request $request)
92 | {
93 | $id = (int) $request->get('id');
94 | $generator = LaravelGenerator::with('template_type')->find($id);
95 | if ($generator) {
96 | if ($generator->template_type->name == LaravelGeneratorType::MODEL) {
97 | return $this->error(trans('laravel-generator::generator.modelNotDelete'));
98 | }
99 | if ($generator->delete()) {
100 | $count = LaravelGenerator::where('template_id', $generator->template_id)->count();
101 | //
102 | if ($count == 0) {
103 | LaravelGeneratorType::whereId($generator->template_id)->delete();
104 | }
105 |
106 | return $this->success(trans('laravel-generator::generator.deleteSuccess'));
107 | }
108 | }
109 |
110 | return $this->error(trans('laravel-generator::generator.deleteFailed'));
111 | }
112 |
113 | public function updateType(Request $request)
114 | {
115 | $name = $request->get('name');
116 | $id = $request->get('id');
117 | if ($id > 0) {
118 | $generator_type = LaravelGeneratorType::whereId($id)->first();
119 | } else {
120 | $generator_type = new LaravelGeneratorType;
121 | }
122 | $generator_type->name = $name;
123 | $generator_type->save();
124 |
125 | return $this->success($generator_type->toArray());
126 | }
127 |
128 | /**
129 | * 保存数据.
130 | *
131 | *
132 | * @return \Illuminate\Http\JsonResponse
133 | */
134 | public function save(Request $request)
135 | {
136 | $data = $request->validate([
137 | 'id' => 'required|int',
138 | 'name' => 'required',
139 | 'template_id' => [
140 | 'required',
141 | 'integer',
142 | Rule::exists('laravel_generator_types', 'id'),
143 | ],
144 | 'is_checked' => 'required|boolean',
145 | 'path' => 'required',
146 | 'file_name' => 'required',
147 | 'template' => 'required',
148 | ]);
149 | if (! $data['id']) {
150 | $generator = new LaravelGenerator;
151 | } else {
152 | $generator = LaravelGenerator::findOrFail($data['id']);
153 | }
154 | $generator->fill($data);
155 |
156 | if ($generator->save()) {
157 | return $this->success(trans('laravel-generator::generator.submitSuccess'));
158 | }
159 |
160 | return $this->error(trans('laravel-generator::generator.submitError'));
161 | }
162 |
163 | /**
164 | * 获取模板列表.
165 | *
166 | * @return LaravelGeneratorType[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection
167 | */
168 | private function getTemplateTypes()
169 | {
170 | return LaravelGeneratorType::all()->map(function ($item) {
171 | $data = [];
172 | $data['label'] = $item->name;
173 | $data['value'] = $item->id;
174 |
175 | return $data;
176 | });
177 | }
178 |
179 | /**
180 | * 获取模板数据.
181 | *
182 | *
183 | * @return array
184 | */
185 | private function getForm($id)
186 | {
187 | $form = [
188 | 'id' => 0,
189 | 'is_checked' => true,
190 | 'template_id' => '',
191 | 'template' => '',
192 | 'path' => '',
193 | 'file_name' => '',
194 | ];
195 |
196 | $generator = LaravelGenerator::find($id);
197 | if ($generator) {
198 | $form = $generator->toArray();
199 | }
200 |
201 | return $form;
202 | }
203 |
204 | public function compile(Request $request)
205 | {
206 | $template = $request->get('template');
207 | if(!$template){
208 | return $this->success(['template'=>'']);
209 | }
210 | try {
211 | $result = GeneratorUtils::demo_compile($template);
212 | return $this->success(['template'=>$result]);
213 | }catch (\Exception $exception){
214 | return $this->error($exception->getMessage());
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/src/Database/GeneratorSeeder.php:
--------------------------------------------------------------------------------
1 | addModel();
24 | // 添加控制器
25 | $this->addControllers();
26 | // 添加视图
27 | $this->addViews();
28 | // 添加路由
29 | $this->addRoute();
30 | // add logs
31 | $this->addLogs();
32 | }
33 |
34 | private function addLogs()
35 | {
36 | $count = LaravelGeneratorLog::count();
37 | if ($count === 0) {
38 | $generators = GeneratorUtils::getGenerators();
39 | LaravelGeneratorLog::create([
40 | 'model_name' => 'User',
41 | 'display_name' => 'User List',
42 | 'creator' => 'system',
43 | 'configs' => json_encode([
44 | 'modelName' => 'User',
45 | 'modelDisplayName' => 'User List',
46 | 'foreigns' => [],
47 | 'relationships' => [],
48 | 'templates' => [],
49 | 'create' => [
50 | 'migration', 'migrate', 'ide-helper',
51 | ],
52 | 'primary_key' => 'id',
53 | 'timestamps' => true,
54 | 'soft_deletes' => false,
55 | 'table_fields' => $generators['tableFields'],
56 | ]),
57 | ]);
58 | }
59 | }
60 |
61 | private function addRoute()
62 | {
63 | $type = LaravelGeneratorType::firstOrCreate([
64 | 'name' => LaravelGeneratorType::Route,
65 | ]);
66 | $generator = LaravelGenerator::firstOrNew([
67 | 'name' => 'route',
68 | ]);
69 | if (! $generator->exists) {
70 | $generator->path = 'routes/';
71 | $generator->file_name = 'admin.php';
72 | $generator->is_checked = 1;
73 | $generator->template = $this->getRouteTemplate();
74 | $generator->template_id = $type->id;
75 | $generator->save();
76 | }
77 | }
78 |
79 | private function getRouteTemplate()
80 | {
81 | return <<<'stub'
82 | name('admin.DummySnakeClass.index');
84 | Route::post('DummySnakeClass/update',[DummyClassController::class,'update'])->name('admin.DummySnakeClass.update');
85 | Route::post('DummySnakeClass/delete',[DummyClassController::class,'delete'])->name('admin.DummySnakeClass.delete');
86 | stub;
87 |
88 | }
89 |
90 | /**
91 | * add Model.
92 | */
93 | private function addModel()
94 | {
95 | $type = LaravelGeneratorType::firstOrCreate([
96 | 'name' => LaravelGeneratorType::MODEL,
97 | ]);
98 | $generator = LaravelGenerator::firstOrNew([
99 | 'name' => 'model',
100 | ]);
101 | if (! $generator->exists) {
102 | $generator->path = 'app/Models';
103 | $generator->file_name = 'DummyClass.php';
104 | $generator->is_checked = 1;
105 | $generator->template = $this->getModelTemplate();
106 | $generator->template_id = $type->id;
107 | $generator->save();
108 | }
109 | }
110 |
111 | /**
112 | * add Controllers.
113 | */
114 | private function addControllers()
115 | {
116 | $type = LaravelGeneratorType::firstOrCreate([
117 | 'name' => LaravelGeneratorType::Controllers,
118 | ]);
119 | $generator = LaravelGenerator::firstOrNew([
120 | 'name' => 'Admin Controller',
121 | ]);
122 | $controllerTemps = $this->getControllersTemplate();
123 | if (! $generator->exists) {
124 | $generator->path = 'app/Http/Controllers/Admin/';
125 | $generator->file_name = 'DummyClassController.php';
126 | $generator->is_checked = 1;
127 | $generator->template = $controllerTemps['admin'];
128 | $generator->template_id = $type->id;
129 | $generator->save();
130 | }
131 | }
132 |
133 | /**
134 | * add Views.
135 | */
136 | private function addViews()
137 | {
138 | $type = LaravelGeneratorType::firstOrCreate([
139 | 'name' => LaravelGeneratorType::Views,
140 | ]);
141 |
142 | $generator = LaravelGenerator::firstOrNew([
143 | 'name' => 'index_view',
144 | ]);
145 | $viewTemp = $this->getViewsTemplate();
146 | if (! $generator->exists) {
147 | $generator->path = 'resources/views/admin/DummySnakeClass/';
148 | $generator->file_name = 'index.vue';
149 | $generator->is_checked = 1;
150 | $generator->template = $viewTemp['index'];
151 | $generator->template_id = $type->id;
152 | $generator->save();
153 | }
154 | $generator = LaravelGenerator::firstOrNew([
155 | 'name' => 'update_view',
156 | ]);
157 | if (! $generator->exists) {
158 | $generator->path = 'resources/views/admin/DummySnakeClass/';
159 | $generator->file_name = 'update.vue';
160 | $generator->is_checked = 1;
161 | $generator->template = $viewTemp['update'];
162 | $generator->template_id = $type->id;
163 | $generator->save();
164 | }
165 | }
166 |
167 | /**
168 | * @return array
169 | */
170 | private function getControllersTemplate()
171 | {
172 | $homeTemp = <<get('create_start_time');
194 | \$create_end_time = \$request->get('create_end_time');
195 | @foreach(\$tableFields as \$field)
196 | @if(\$field['can_search'])
197 | \${{\$field['field_name'] }} = \$request->get('{{\$field['field_name'] }}');
198 | @endif
199 | @endforeach
200 | \$data = DummyClass::orderByDesc('id')
201 | @foreach(\$tableFields as \$field)
202 | @if(\$field['can_search'])
203 | @if('numeric'==\$field['rule'])
204 | ->when(\${{\$field['field_name'] }}, fn (Builder \$query) => \$query->where('{{\$field['field_name'] }}', \${{\$field['field_name'] }}))
205 | @elseif('string'==\$field['rule'])
206 | ->when(\${{\$field['field_name'] }}, fn (Builder \$query) => \$query->where('{{\$field['field_name'] }}', 'like', "%\${{\$field['field_name'] }}%"))
207 | @else
208 | ->when(\${{\$field['field_name'] }}, fn (Builder \$query) => \$query->where('{{\$field['field_name'] }}', 'like', "%\${{\$field['field_name'] }}%"))
209 | @endif
210 | @endif
211 | @endforeach
212 | ->when(\$create_start_time, fn (Builder \$query) => \$query->where('created_at', '>=', \$create_start_time))
213 | ->when(\$create_end_time, fn (Builder \$query) => \$query->where('created_at', '<=', \$create_end_time))
214 | ->paginate();
215 |
216 | \$data->getCollection()->transform(function (DummyClass \$DummySnakeClass){
217 | //\$DummySnakeClass->setAttribute('id', 'ID');
218 |
219 | return \$DummySnakeClass;
220 | });
221 |
222 | return response()->json(['message' => 'success', 'errcode' => 0, 'data' => \$data->toArray()]);
223 | }
224 |
225 | public function update(Request \$request)
226 | {
227 | \$id = (int)\$request->get('id');
228 | \$DummySnakeClass = null;
229 | if(\$id){
230 | \$DummySnakeClass = DummyClass::whereId(\$id)->first();
231 | }
232 | \$data=\$request->validate([
233 | 'id' => 'required|int',
234 | @foreach(\$tableFields as \$field)
235 | @if('string'==\$field['rule'] && false==\$field['nullable'])
236 | '{{\$field['field_name'] }}' => 'required'
237 | @endif
238 | @endforeach
239 | ],[],[
240 | 'id' => 'ID',
241 | @foreach(\$tableFields as \$field)
242 | @if('string'==\$field['rule'] && false==\$field['nullable'])
243 | '{{\$field['field_name'] }}' => '{{\$field['field_display_name'] }}'
244 | @endif
245 | @endforeach
246 | ]);
247 |
248 | if(!\$DummySnakeClass){
249 | \$DummySnakeClass=new DummyClass();
250 | }
251 | \$DummySnakeClass->fill(\$data);
252 | if(\$DummySnakeClass->save()){
253 | return response()->json(['message' => '保存成功', 'errcode' => 0, 'data' => []]);
254 | }
255 | return response()->json(['message' => '保存失败', 'errcode' => 1, 'data' => []]);
256 | }
257 |
258 | public function delete(Request \$request)
259 | {
260 | \$id = (int)\$request->get('id');
261 | \$DummySnakeClass = DummyClass::whereId(\$id)->first();
262 | if(\$DummySnakeClass && \$DummySnakeClass->delete()){
263 | return response()->json(['message' => '删除成功', 'errcode' => 0, 'data' => []]);
264 | }
265 | return response()->json(['message' => '删除失败', 'errcode' => 1, 'data' => []]);
266 | }
267 | }
268 | stub;
269 |
270 | return [
271 | 'admin' => $homeTemp,
272 | ];
273 | }
274 |
275 | /**
276 | * @return array
277 | */
278 | private function getViewsTemplate()
279 | {
280 | $index_temp = <<<'stub'
281 |
282 |
283 |
284 | @foreach($tableFields as $field)
285 | @if($field['can_search'] && 'string'==$field['rule'])
286 |
287 |
288 |
289 |
290 |
291 | @endif
292 | @endforeach
293 |
294 |
295 | 查询
296 | 添加
297 |
298 |
299 |
300 |
301 |
302 |
308 |
312 |
313 | @foreach($tableFields as $field)
314 | @if($field['is_list_display'])
315 |
319 |
320 | @endif
321 | @endforeach
322 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
344 |
345 |
346 |
347 |
348 |
355 |
357 | stub;
358 | $update_temp = <<<'stub'
359 |
360 |
382 | >
383 |
390 |
392 | stub;
393 |
394 | return [
395 | 'index' => $index_temp,
396 | 'update' => $update_temp,
397 | ];
398 | }
399 |
400 | /**
401 | * get the model template.
402 | *
403 | * @return string
404 | */
405 | private function getModelTemplate()
406 | {
407 | return ' */
422 | use HasFactory;
423 | @if($modelFields[\'soft_deletes\'])
424 | use SoftDeletes;
425 | @endif
426 | @if(!$modelFields[\'timestamps\'])
427 | public $timestamps = false;
428 | @endif
429 |
430 | @foreach($relationShips as $relationship)
431 | @if(\'hasMany\'==$relationship[\'relationship\'])
432 | public function {{$relationship[\'snake_plural_model\']}}(){
433 | return $this->hasMany({{$relationship[\'model\']}}::class @if($relationship[\'foreign_key\']),\'{{$relationship[\'foreign_key\']}}\'@endif);
434 | }
435 | @else
436 | public function {{$relationship[\'snake_model\']}}(){
437 | return $this->{{$relationship[\'relationship\']}}({{$relationship[\'model\']}}::class @if($relationship[\'foreign_key\']),\'{{$relationship[\'foreign_key\']}}\'@endif);
438 | }
439 | @endif
440 | @endforeach
441 | }';
442 | }
443 | }
444 |
--------------------------------------------------------------------------------
/src/FileCreator.php:
--------------------------------------------------------------------------------
1 | file_real_name = $file_real_name;
42 | $this->template = $template;
43 | $this->files = app('files');
44 | }
45 |
46 | /**
47 | * @return string
48 | *
49 | * @throws \Exception
50 | */
51 | public function create()
52 | {
53 | $path = base_path($this->file_real_name);
54 |
55 | if ($this->files->exists($path)) {
56 | throw new \Exception("file [$this->file_real_name] already exists!");
57 | }
58 |
59 | if (!$this->files->isDirectory(dirname($path))) {
60 | try {
61 | $this->files->makeDirectory(dirname($path), 0755, true);
62 | } catch (\Exception $exception) {
63 | throw new \Exception($exception->getMessage().$path);
64 | }
65 | }
66 | $this->files->put($path, $this->template);
67 |
68 | return $path;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/GeneratorServiceProvider.php:
--------------------------------------------------------------------------------
1 | loadViewsFrom(__DIR__.'/../resources/views', 'laravel-generator');
18 |
19 | //the language
20 | $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'laravel-generator');
21 |
22 | // load migrations
23 | $this->loadMigrationsFrom(__DIR__.'/../resources/migrations');
24 |
25 | // Publishing generator files.
26 | $this->publishes([
27 | __DIR__.'/../config/laravel-generator.php' => config_path('laravel-generator.php'),
28 | ],'laravel-generator');
29 |
30 | //routes
31 | $this->loadRoutesFrom(__DIR__.'/../routes/route.php');
32 |
33 | if ($this->app->runningInConsole()) {
34 | $this->commands([
35 | InstallCommand::class,
36 | ]);
37 | }
38 | }
39 |
40 | /**
41 | * Register any package services.
42 | */
43 | public function register()
44 | {
45 | $this->mergeConfigFrom(
46 | __DIR__.'/../config/laravel-generator.php', 'laravel-generator'
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/GeneratorUtils.php:
--------------------------------------------------------------------------------
1 | $placeholder) {
42 | if (isset($laravel_generators[$key])) {
43 | $replacements[$placeholder] = $laravel_generators[$key];
44 | }
45 | }
46 | $data = array_merge($laravel_generators,[
47 | 'customKeys' => static::getCustomKeys()
48 | ]);
49 | try {
50 | $result = Blade::render($template,$data);
51 | $replacements['#php#'] = 'getMessage()." in line-".$exception->getLine());
56 | }
57 | }
58 | public static function compile($template,array $data) :string
59 | {
60 | $template = str_replace(' $data['primary_key'],
67 | 'timestamps' => (bool)$data['timestamps'],
68 | 'soft_deletes' => (bool)$data['soft_deletes'],
69 | ];
70 | // 可用的假属性字段
71 | $replacements = static::getDummyValues($data['modelName']);
72 | $replacements['DummyDisplayName'] = $data['modelDisplayName'];
73 | $generators = array_merge($generators,[
74 | 'customKeys' => static::getCustomKeys()
75 | ]);
76 | try {
77 | $result = Blade::render($template,$generators);
78 | $replacements['#php#'] = 'getMessage()." in line-".$exception->getLine());
83 | }
84 | }
85 | /**
86 | * get all of tables in the default database.
87 | */
88 | public static function getTables(): array
89 | {
90 | $info = [];
91 | $driver = DB::getDriverName();
92 | $database = DB::getConfig('database');
93 | $prefix = DB::getConfig('prefix');
94 |
95 | $tableNames = match ($driver) {
96 | 'sqlite' => array_map(
97 | fn ($row) => $row->name,
98 | DB::select("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
99 | ),
100 |
101 | 'mysql' => array_map(
102 | fn ($row) => $row->{"Tables_in_$database"},
103 | DB::select('SHOW TABLES')
104 | ),
105 |
106 | 'pgsql' => array_map(
107 | fn ($row) => $row->tablename,
108 | DB::select("SELECT tablename FROM pg_tables WHERE schemaname = 'public'")
109 | ),
110 |
111 | default => throw new \RuntimeException("Unsupported DB driver: $driver"),
112 | };
113 | $ignoreTables = static::ignoreTables();
114 | foreach ($tableNames as $table) {
115 | if (in_array($table, $ignoreTables)) {
116 | continue;
117 | }
118 | $cleanName = $prefix ? str_replace($prefix, '', $table) : $table;
119 | $info[] = [
120 | 'name' => $cleanName,
121 | 'columns' => Schema::getColumnListing($table),
122 | ];
123 | }
124 |
125 | return $info;
126 | }
127 |
128 | public static function ignoreTables(): array
129 | {
130 | return [
131 | 'migrations',
132 | 'laravel_generators',
133 | 'laravel_generator_configs',
134 | 'laravel_generator_logs',
135 | 'laravel_generator_types',
136 | ];
137 | }
138 | /**
139 | * get general Engines.
140 | *
141 | * @return array
142 | */
143 | public static function getGeneralEngines()
144 | {
145 | $engines = [];
146 | $dbEngines = ['InnoDB', 'MyISAM', 'MEMORY', 'ARCHIVE'];
147 | foreach ($dbEngines as $k => $engine) {
148 | $engines[$k]['label'] = $engine;
149 | $engines[$k]['value'] = $engine;
150 | }
151 |
152 | return $engines;
153 | }
154 |
155 | /**
156 | * get dbTypes.
157 | *
158 | * @return array
159 | */
160 | public static function getDbTypes()
161 | {
162 | $dbTypes = [];
163 | $types = [
164 | 'string', 'integer', 'text', 'float', 'double', 'decimal', 'boolean', 'date', 'time',
165 | 'dateTime', 'timestamp', 'char', 'mediumText', 'longText', 'tinyInteger', 'smallInteger',
166 | 'mediumInteger', 'bigInteger', 'unsignedTinyInteger', 'unsignedSmallInteger', 'unsignedMediumInteger',
167 | 'unsignedInteger', 'unsignedBigInteger', 'enum', 'json', 'jsonb', 'dateTimeTz', 'timeTz',
168 | 'timestampTz', 'nullableTimestamps', 'binary', 'ipAddress', 'macAddress',
169 | ];
170 | foreach ($types as $k => $type) {
171 | $dbTypes[$k]['label'] = $type;
172 | $dbTypes[$k]['value'] = $type;
173 | }
174 |
175 | return $dbTypes;
176 | }
177 |
178 | /**
179 | * 获取可用的假字段.
180 | *
181 | * @return array
182 | */
183 | public static function getDummyAttrs()
184 | {
185 | return [
186 | 'className' => 'DummyClass',
187 | 'classDisplayName' => 'DummyDisplayName',
188 | 'camelClassName' => 'DummyCamelClass',
189 | 'snakeClassName' => 'DummySnakeClass',
190 | 'pluralClassName' => 'DummyPluralClass',
191 | 'snakePluralClassName' => 'DummySnakePluralClass',
192 | ];
193 | }
194 | public static function getCustomKeys()
195 | {
196 | return config('laravel-generator.custom_keys', []);
197 | }
198 |
199 | public static function getTags():array
200 | {
201 | return [
202 | [
203 | 'name'=>'Controller',
204 | 'path'=>'app/Http/Controllers/Admin/',
205 | 'file'=>'DummyClassController.php',
206 | 'type'=>'primary',
207 | ],
208 | [
209 | 'name'=>'Test',
210 | 'path'=>'tests/Unit',
211 | 'file'=>'DummyClassTest.php',
212 | 'type'=>'danger',
213 | ],
214 | [
215 | 'name'=>'Vue',
216 | 'path'=>'resources/views/admin/DummySnakeClass/',
217 | 'file'=>'index.vue',
218 | 'type'=>'warning',
219 | ],
220 | [
221 | 'name'=>'Request',
222 | 'path'=>'app/Http/Requests/',
223 | 'file'=>'DummyClassRequest.php',
224 | 'type'=>'success',
225 | ]
226 | ];
227 | }
228 |
229 | /**
230 | * 根据名称获取转换的字段的值
231 | *
232 | * @param $modelName 名称
233 | * @return array
234 | */
235 | public static function getDummyValues($modelName)
236 | {
237 | return [
238 | 'DummyClass' => $modelName,
239 | 'DummyCamelClass' => Str::camel($modelName),
240 | 'DummySnakeClass' => Str::snake($modelName),
241 | 'DummyPluralClass' => Str::plural($modelName),
242 | 'DummySnakePluralClass' => Str::snake(Str::plural($modelName)),
243 | ];
244 | }
245 |
246 | /**
247 | * 获取函数数据.
248 | *
249 | * @return array
250 | */
251 | public static function getFunctions()
252 | {
253 | return [
254 | // the if
255 | 'if' => '@if(true)
256 |
257 | @else
258 |
259 | @endif',
260 | // the elseif
261 | 'elseif' => '@if(true)
262 |
263 | @elseif
264 |
265 | @else
266 |
267 | @endif',
268 | // the tableFieldsFor
269 | 'for' => '@foreach($tableFields as $field)
270 | {{ $field[\'field_name\'] }}
271 | @endforeach',
272 |
273 | // the tableFieldsFor
274 | 'soft_deletes' => '@if($modelFields[\'soft_deletes\'])
275 |
276 | @endif
277 | ',
278 | 'timestamps' => '@if($modelFields[\'timestamps\'])
279 |
280 | @endif
281 | ',
282 | 'primary_key' => '{{ $modelFields[\'primary_key\']}}',
283 | // the tableFieldsFor
284 | 'fillable' => 'protected \$fillable = [@foreach($tableFields as $field) @if($field[\'field_name\']!=\'id\')\'{{ $field[\'field_name\'] }}\',@endif @endforeach];',
285 |
286 | // the rule
287 | 'rule' => '@foreach($tableFields as $field)
288 | @if(\'file\'==$field[\'rule\'])
289 |
290 | @endif
291 | @endforeach',
292 | 'relationships' => '@foreach($relationShips as $relationship)
293 | @if(\'hasMany\'==$relationship[\'relationship\'])
294 | public function {{$relationship[\'snake_plural_model\']}}(){
295 | return $this->hasMany({{$relationship[\'model\']}}::class @if($relationship[\'foreign_key\']),\'{{$relationship[\'foreign_key\']}}\'@endif);
296 | }
297 | @else
298 | public function {{$relationship[\'snake_model\']}}(){
299 | return $this->{{$relationship[\'relationship\']}}({{$relationship[\'model\']}}::class @if($relationship[\'foreign_key\']),\'{{$relationship[\'foreign_key\']}}\'@endif);
300 | }
301 | @endif
302 | @endforeach',
303 | ];
304 | }
305 |
306 | /**
307 | * @return array
308 | */
309 | public static function getGenerators()
310 | {
311 | return [
312 | 'className' => 'LaravelGenerator',
313 | 'classDisplayName' => 'my laravel generator',
314 | 'camelClassName' => 'laravelGenerator',
315 | 'snakeClassName' => 'laravel_generator',
316 | 'pluralClassName' => 'LaravelGenerators',
317 | 'snakePluralClassName' => 'laravel_generators',
318 | 'tableFields' => [
319 | [
320 | 'field_name' => 'user_id',
321 | 'field_display_name' => 'User Id',
322 | 'type' => 'integer',
323 | 'attach' => '',
324 | 'nullable' => false,
325 | 'key' => '',
326 | 'is_list_display' => true,
327 | 'can_search' => true,
328 | 'rule' => 'numeric',
329 | ],
330 | [
331 | 'field_name' => 'name',
332 | 'field_display_name' => trans('laravel-generator::generator.name'),
333 | 'type' => 'string',
334 | 'attach' => '255',
335 | 'nullable' => false,
336 | 'key' => 'unique',
337 | 'is_list_display' => true,
338 | 'can_search' => true,
339 | 'rule' => 'string',
340 | ],
341 | [
342 | 'field_name' => 'add_time',
343 | 'field_display_name' => trans('laravel-generator::generator.addTime'),
344 | 'type' => 'timestamp',
345 | 'nullable' => true,
346 | 'key' => '',
347 | 'is_list_display' => true,
348 | 'can_search' => true,
349 | 'rule' => 'date',
350 | ],
351 | [
352 | 'field_name' => 'upload_file',
353 | 'field_display_name' => trans('laravel-generator::generator.file'),
354 | 'type' => 'string',
355 | 'nullable' => true,
356 | 'key' => '',
357 | 'is_list_display' => true,
358 | 'can_search' => false,
359 | 'rule' => 'file',
360 | ],
361 | ],
362 | 'modelFields' => [
363 | 'primary_key' => 'id',
364 | 'timestamps' => true,
365 | 'soft_deletes' => true,
366 | ],
367 | 'relationShips' => [
368 | [
369 | 'relationship' => 'belongsTo',
370 | 'model' => 'LaravelGeneratorType',
371 | 'camel_model' => 'laravelGeneratorType',
372 | 'snake_model' => 'laravel_generator_type',
373 | 'snake_plural_model' => 'laravel_generator_types',
374 | 'foreign_key' => 'template_id',
375 | 'reverse' => 'hasMany',
376 | 'with' => true,
377 | 'can_search' => true,
378 | ],
379 | ],
380 | ];
381 | }
382 |
383 | public static function getDoctrineTable(string $tableName): Table
384 | {
385 | // 获取 Laravel 当前连接配置
386 | $config = config('database.connections.' . config('database.default'));
387 |
388 | // 转换为 Doctrine DBAL 配置
389 | $doctrineConfig = match ($config['driver']) {
390 | 'mysql' => [
391 | 'dbname' => $config['database'],
392 | 'user' => $config['username'],
393 | 'password' => $config['password'],
394 | 'host' => $config['host'],
395 | 'port' => $config['port'] ?? 3306,
396 | 'driver' => 'pdo_mysql',
397 | 'charset' => $config['charset'] ?? 'utf8mb4',
398 | ],
399 | 'pgsql' => [
400 | 'dbname' => $config['database'],
401 | 'user' => $config['username'],
402 | 'password' => $config['password'],
403 | 'host' => $config['host'],
404 | 'port' => $config['port'] ?? 5432,
405 | 'driver' => 'pdo_pgsql',
406 | ],
407 | 'sqlite' => [
408 | 'driver' => 'pdo_sqlite',
409 | 'path' => $config['database'],
410 | ],
411 | default => throw new \RuntimeException('Unsupported driver: ' . $config['driver']),
412 | };
413 |
414 | // 创建 Doctrine Connection
415 | $connection = DriverManager::getConnection($doctrineConfig);
416 | $schemaManager = $connection->createSchemaManager();
417 | // 返回 Table 元信息
418 | return $schemaManager->introspectTable($tableName);
419 | }
420 |
421 | /**
422 | * get table columns by table name
423 | * @param $table table name
424 | * @return array columns
425 | * @throws \Doctrine\DBAL\Exception
426 | */
427 | public static function getTableColumns($table): array
428 | {
429 | $table_name = config('database.connections.' . config('database.default').'.prefix').$table;
430 | $columns = static::getDoctrineTable($table_name)->getColumns();
431 | $res = [
432 | 'primary_key' => '',
433 | 'table_fields' => [],
434 | ];
435 | $i = 0;
436 | foreach ($columns as $column) {
437 | $table_field = [];
438 | $is_auto_increment = $column->getAutoincrement();
439 | if(!$is_auto_increment) {
440 | $type = $column->getType();
441 | $table_field['field_name'] = $column->getName();
442 | $table_field['field_display_name'] = $column->getName();
443 | $type_name = $type::getTypeRegistry()->lookupName($type);
444 | $table_field['type'] = static::typeTransformer($type_name);
445 | $attach = '';
446 | if ( $type instanceof DecimalType || $type instanceof FloatType) {
447 | $attach .= $column->getPrecision()??'';
448 | $attach .= $column->getScale()?','.$column->getScale():'';
449 | } else {
450 | $attach .= $column->getLength()??'';
451 | }
452 | $table_field['attach'] = $attach;
453 | $table_field['can_search'] = false;
454 | $table_field['key'] = '';
455 | $table_field['rule'] = '';
456 | $table_field['is_list_display'] = false;
457 | $table_field['nullable'] = $column->getNotnull();
458 | $table_field['default'] = $column->getDefault();
459 | $table_field['comment'] = $column->getComment();
460 | $res['table_fields'][$i] = $table_field;
461 | $i++;
462 | }else{
463 | $res['primary_key'] = $column->getName();
464 | }
465 |
466 | }
467 |
468 | return $res;
469 | }
470 |
471 | public static function typeTransformer($type)
472 | {
473 | return match ($type) {
474 | 'datetime' => 'dateTime',
475 | 'datetimetz' => 'dateTimeTz',
476 | 'bigint' => 'bigInteger',
477 | default => $type,
478 | };
479 | }
480 |
481 | /**
482 | * @throws Exception
483 | */
484 | public static function tableToForm($table_name): array
485 | {
486 | $result = [
487 | "id" => 0,
488 | "create" => [],
489 | "foreigns" =>[],
490 | "timestamps" =>false,
491 | "soft_deletes" =>false,
492 | "modelName" => static::modelFromTable($table_name),
493 | "templates" => [],
494 | "modelDisplayName" => $table_name,
495 | "relationships" => []
496 | ];
497 | $table_columns = static::getTableColumns($table_name);
498 | $fields = $table_columns['table_fields'];
499 | $hasCreatedAt = false;
500 | $hasUpdatedAt = false;
501 | foreach ($fields as $field) {
502 | if ($field['field_name'] === 'created_at') {
503 | $hasCreatedAt = true;
504 | }
505 | if ($field['field_name'] === 'updated_at') {
506 | $hasUpdatedAt = true;
507 | }
508 | }
509 | if ($hasCreatedAt && $hasUpdatedAt) {
510 | $table_columns['table_fields'] = array_values(array_filter($fields, function ($field) {
511 | return !in_array($field['field_name'], ['created_at', 'updated_at']);
512 | }));
513 | $result['timestamps'] = true;
514 | }
515 |
516 | return array_merge($result, $table_columns);
517 |
518 | }
519 |
520 |
521 | public static function modelFromTable(string $table): ?string {
522 | return Str::studly(Str::singular($table));
523 | }
524 | }
525 |
--------------------------------------------------------------------------------
/src/Message.php:
--------------------------------------------------------------------------------
1 | json(['message' => 'success', 'errcode' => 0, 'data' => $data]);
27 | }
28 |
29 | /**
30 | *
31 | * @param $message
32 | * @param int $errcode
33 | * @return \Illuminate\Http\JsonResponse
34 | */
35 | public function error($message, $errcode=1)
36 | {
37 | return response()->json(['message' => $message, 'errcode' => $errcode, 'data' => []]);
38 | }
39 | }
--------------------------------------------------------------------------------
/src/MigrationCreator.php:
--------------------------------------------------------------------------------
1 | ensureMigrationDoesntAlreadyExist($name);
31 |
32 | $path = $this->getPath($name, $path);
33 | $stub = $this->get_stub();
34 |
35 | $this->isCreate = $create;
36 | $this->files->put($path, $this->replaceStub($name, $stub, $table));
37 |
38 | return $path;
39 | }
40 |
41 | /**
42 | * Build the table blueprint.
43 | *
44 | * @param array $fields
45 | * @param string $keyName
46 | * @param bool|true $useTimestamps
47 | * @param bool|false $softDeletes
48 | *
49 | * @throws \Exception
50 | *
51 | * @return $this
52 | */
53 | public function buildBluePrint($fields = [], $keyName = 'id', $useTimestamps = true, $softDeletes = false, $foreigns = [])
54 | {
55 | $fields = array_filter($fields, function ($field) {
56 | return isset($field['field_name']) && !empty($field['field_name']);
57 | });
58 |
59 | if (empty($fields)) {
60 | throw new \Exception('Table fields can\'t be empty');
61 | }
62 |
63 | //设置字段
64 | $this->fields = $fields;
65 | $rows = [];
66 | if (isset($keyName)) {
67 | $rows[] = "\$table->increments('$keyName');\n";
68 | }
69 | foreach ($fields as $k => $field) {
70 | if (isset($field['attach'])) {
71 | $column = "\$table->{$field['type']}('{$field['field_name']}',{$field['attach']})";
72 | } else {
73 | $column = "\$table->{$field['type']}('{$field['field_name']}')";
74 | }
75 |
76 | if ($field['key']) {
77 | $column .= "->{$field['key']}()";
78 | }
79 |
80 | if (isset($field['default']) && $field['default']) {
81 | $column .= "->default('{$field['default']}')";
82 | }
83 |
84 | if (isset($field['comment']) && $field['comment']) {
85 | $column .= "->comment('{$field['comment']}')";
86 | }
87 |
88 | if (isset($field['nullable']) && $field['nullable']) {
89 | $column .= '->nullable()';
90 | }
91 | if (isset($field['change']) && $field['change']) {
92 | $column .= '->change()';
93 | }
94 | $rows[] = $column.";\n";
95 | }
96 |
97 | if ($useTimestamps) {
98 | $rows[] = "\$table->timestamps();\n";
99 | }
100 |
101 | if ($softDeletes) {
102 | $rows[] = "\$table->softDeletes();\n";
103 | }
104 |
105 | //添加关联关系
106 | if ($foreigns) {
107 | $rows[] = "\n";
108 | foreach ($foreigns as $foreign) {
109 | $onDelete = '';
110 | if (isset($foreign['onDelete']) && $foreign['onDelete']) {
111 | $onDelete = "->onDelete('{$foreign['onDelete']}')";
112 | }
113 | $onUpdate = '';
114 | if (isset($foreign['onUpdate']) && $foreign['onUpdate']) {
115 | $onUpdate = "->onUpdate('{$foreign['onUpdate']}')";
116 | }
117 | $rows[] = "\$table->foreign('{$foreign['foreign']}')->references('{$foreign['references']}')->on('{$foreign['on']}'){$onDelete}{$onUpdate};\n";
118 | }
119 | }
120 |
121 | $this->bluePrint = trim(implode(str_repeat(' ', 12), $rows), "\n");
122 |
123 | return $this;
124 | }
125 |
126 | /**
127 | * Populate stub.
128 | *
129 | * @param string $name
130 | * @param string $stub
131 | * @param string $table
132 | *
133 | * @return mixed
134 | */
135 | protected function replaceStub($name, $stub, $table)
136 | {
137 | $type = $this->isCreate ? 'create' : 'table';
138 | if ($this->isCreate) {
139 | //删除表
140 | $down = "Schema::dropIfExists('{$table}');";
141 | } else {
142 | //删除修改表的字段
143 | $down = "Schema::table('{$table}', function (Blueprint \$table) {\n";
144 | foreach ($this->fields as $field) {
145 | if (!$field['change']) {
146 | $down .= " \$table->dropColumn('{$field['field_name']}');\n";
147 | }
148 | }
149 | $down .= ' });';
150 | }
151 |
152 | return str_replace(
153 | ['DummyClass', 'DummyTable', 'DummyStructure', 'create', 'DummyDownTable'],
154 | [$this->getClassName($name), $table, $this->bluePrint, $type, $down],
155 | $stub
156 | );
157 | }
158 |
159 | private function get_stub()
160 | {
161 | return << 'boolean',
18 | ];
19 |
20 | /**
21 | * 设置路径
22 | *
23 | * @param $value
24 | */
25 | public function setPathAttribute($value)
26 | {
27 | $this->attributes['path'] = trim($value,'/').'/';
28 | }
29 |
30 | /**
31 | * 设置文件名
32 | *
33 | * @param $value
34 | */
35 | public function setFileNameAttribute($value)
36 | {
37 | $this->attributes['file_name'] = trim($value,'/');
38 | }
39 | /**
40 | *
41 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
42 | */
43 | public function template_type()
44 | {
45 | return $this->belongsTo(LaravelGeneratorType::class,'template_id','id');
46 | }
47 |
48 | /**
49 | * 设置是否选中
50 | *
51 | * @param $value
52 | */
53 | public function setIsCheckedAttribute($value)
54 | {
55 | $this->attributes['is_checked'] = (int)$value;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Models/LaravelGeneratorConfig.php:
--------------------------------------------------------------------------------
1 | |LaravelGeneratorConfig newModelQuery()
17 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig newQuery()
18 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig query()
19 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig whereAlias($value)
20 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig whereConfig($value)
21 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig whereCreatedAt($value)
22 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig whereId($value)
23 | * @method static \Illuminate\Database\Eloquent\Builder|LaravelGeneratorConfig whereUpdatedAt($value)
24 | * @mixin \Eloquent
25 | */
26 | class LaravelGeneratorConfig extends Model
27 | {
28 |
29 | protected $fillable = ['alias','config','group',];
30 |
31 |
32 |
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/Models/LaravelGeneratorLog.php:
--------------------------------------------------------------------------------
1 | format('Y-m-d H:i:s');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Models/LaravelGeneratorType.php:
--------------------------------------------------------------------------------
1 | hasMany(LaravelGenerator::class,'template_id','id');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/GeneratorUtilsTest.php:
--------------------------------------------------------------------------------
1 | getPrimaryKey();
9 | dump($res);
10 | expect($res)->not->toBeEmpty();
11 | });
12 | test('get table columns', function () {
13 | $table = 'laravel_generators';
14 | $columns = GeneratorUtils::getTableColumns($table);
15 | dump($columns);
16 | expect($columns)->not->toBeEmpty();
17 | });
18 |
19 | test('table to form', function () {
20 | $table = 'laravel_generators';
21 | $columns = GeneratorUtils::tableToForm($table);
22 | expect($columns)->not->toBeEmpty();
23 | });
24 |
--------------------------------------------------------------------------------
/tests/LaravelGeneratorLogTest.php:
--------------------------------------------------------------------------------
1 | count(5)->create();
8 | expect(LaravelGeneratorLog::count())->toBeGreaterThan(0);
9 | });
10 |
--------------------------------------------------------------------------------