├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── config └── .gitkeep ├── database └── migrations │ └── 2016_06_01_102904_create_db_tables_and_columns_and_categories_tables.php ├── src ├── Console │ └── SyncCommand.php ├── Controllers │ └── DictController.php ├── LavavelDbDictProvider.php ├── Models │ ├── DbCategory.php │ ├── DbColumn.php │ └── DbTable.php └── routes.php └── views └── index.blade.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 zhuzhichao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Laravel 5 DB Dict 2 | ====================== 3 | 4 | Version: 0.1.7 5 | ---- 6 | 数据字典 for laravel。 7 | 8 | 团队中经常要沟通表和字段, 免不了写文档, 但是文档永远不够及时和准确, 这样就会给团队带来很多的不必要但是也不可避免的麻烦。 9 | 10 | 虽然有一部分在线的数据字典(但是很少很少的选择),还是需要大家在更新数据库之后手动更新。 11 | 12 | 所以这个 Laravel 扩展应运而生! 能够做到实时的、自动的、准确的、优雅的数据字典。 13 | 14 | ##目前进度 15 | 16 | 1. 控制器、模型、迁移文件、命令行工具 17 | 2. 将项目的数据表和字段信息同步到字典 18 | 3. 字典的路由和列表页面 19 | 4. 正常的显示所有表和字段 20 | 1. 表和字段的描述更新 21 | 3. 列表页面布局优化 22 | 4. 页面添加同步字段按钮 23 | 24 | ##Todos 25 | 26 | 5. 提供显示删除的字段和表 27 | 6. 提供英文版本和多语言支持 28 | 7. 表分类显示 29 | 30 | ## Demo 31 | 32 | ![laravel-db-dict-demo](http://7xkxib.com1.z0.glb.clouddn.com/laravel-db-dict-demo-2.png) 33 | 34 | ## Installation 35 | 36 | ### 安装 37 | composer require zhuzhichao/laravel-db-dict 38 | 39 | ### 配置 40 | add follow line into config/app.php>providers>array 41 | 42 | ``` 43 | Zhuzhichao\LaravelDbDict\LavavelDbDictProvider::class 44 | ``` 45 | 46 | php artisan vendor:publish 47 | 48 | php artisan migrate 49 | 50 | ### 同步数据字典 51 | php artisan db:dict-sync 52 | 53 | ## Usage 54 | open Chrome and tap http://yourhost/laravel-db-dict -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zhuzhichao/laravel-db-dict", 3 | "description": "A Laravel db dict package", 4 | "license": "MIT", 5 | "keywords": ["db-dict", "laravel", "database", "dict"], 6 | "authors": [ 7 | { 8 | "name": "zhuzhichao", 9 | "email": "me@zhuzhichao.com" 10 | } 11 | ], 12 | "require": { 13 | "php": "^5.5.9 || ^7.0" 14 | }, 15 | "autoload": { 16 | "psr-4": { 17 | "Zhuzhichao\\LaravelDbDict\\": "src/" 18 | } 19 | }, 20 | "minimum-stability": "stable" 21 | } 22 | -------------------------------------------------------------------------------- /config/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/migrations/2016_06_01_102904_create_db_tables_and_columns_and_categories_tables.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->text('remark')->nullable(); 20 | $table->timestamps(); 21 | }); 22 | 23 | Schema::create('db_tables', function (Blueprint $table) { 24 | $table->increments('id'); 25 | $table->integer('category_id')->unsigned()->nullable(); 26 | $table->string('name'); 27 | $table->text('alias')->nullable(); 28 | $table->text('description')->nullable(); 29 | $table->boolean('is_hidden')->default(false); 30 | $table->softDeletes(); 31 | $table->timestamps(); 32 | }); 33 | 34 | Schema::create('db_columns', function (Blueprint $table) { 35 | $table->increments('id'); 36 | $table->string('table_id')->nullable()->index(); 37 | $table->string('name')->nullable(); 38 | $table->string('type')->nullable(); 39 | $table->string('default')->nullable(); 40 | $table->string('key')->nullable(); 41 | $table->boolean('is_nullable'); 42 | $table->string('extra')->nullable(); 43 | $table->string('comment')->nullable(); 44 | $table->string('alias')->nullable(); 45 | $table->text('description')->nullable(); 46 | $table->softDeletes(); 47 | $table->timestamps(); 48 | }); 49 | } 50 | 51 | /** 52 | * Reverse the migrations. 53 | * 54 | * @return void 55 | */ 56 | public function down() 57 | { 58 | Schema::dropIfExists('db_table_categories'); 59 | Schema::dropIfExists('db_tables'); 60 | Schema::dropIfExists('db_columns'); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Console/SyncCommand.php: -------------------------------------------------------------------------------- 1 | dbName = DB::getDatabaseName(); 30 | parent::__construct(); 31 | } 32 | 33 | /** 34 | * Execute the console command. 35 | * 36 | * @return mixed 37 | */ 38 | public function handle() 39 | { 40 | 41 | $tables = $this->syncTables(); 42 | $this->syncColumns($tables); 43 | 44 | } 45 | 46 | public function syncTables() 47 | { 48 | $tableSql = "select table_name from (select t.table_schema as db_name, 49 | t.table_name, 50 | (case when t.table_type = 'BASE TABLE' then 'table' 51 | when t.table_type = 'VIEW' then 'view' 52 | else t.table_type 53 | end) as table_type, 54 | c.column_name, 55 | c.column_type, 56 | c.column_default, 57 | c.column_key, 58 | c.is_nullable, 59 | c.extra, 60 | c.column_comment 61 | from information_schema.tables as t 62 | inner join information_schema.columns as c 63 | on t.table_name = c.table_name 64 | and t.table_schema = c.table_schema 65 | where t.table_type in('base table', 'view') 66 | and t.table_schema = '{$this->dbName}' 67 | order by t.table_schema, t.table_name, c.ordinal_position) as all_columns group by table_name"; 68 | 69 | $tableNames = array_pluck((array) DB::select($tableSql), 'table_name'); 70 | $this->info("共有".count($tableNames)."张表, 将同步表信息"); 71 | $bar = $this->output->createProgressBar(count($tableNames)); 72 | foreach ($tableNames as $tableName) { 73 | $tableBuilder = DbTable::withTrashed()->where('name', $tableName); 74 | if ($tableBuilder->exists()) { 75 | $table = $tableBuilder->first(); 76 | if ($table->trashed()) { 77 | $table->restore(); 78 | } 79 | } else { 80 | DbTable::create([ 81 | 'name' => $tableName 82 | ]); 83 | } 84 | $bar->advance(); 85 | } 86 | DbTable::whereNotIn('name', $tableNames)->delete(); 87 | $bar->finish(); 88 | 89 | return DbTable::all(); 90 | } 91 | 92 | private function syncColumns($tables) 93 | { 94 | $bar = $this->output->createProgressBar(count($tables)); 95 | /** @var DbTable $table */ 96 | foreach ($tables as $table) { 97 | $columnSql = "select t.table_schema as db_name, 98 | t.table_name, 99 | (case when t.table_type = 'BASE TABLE' then 'table' 100 | when t.table_type = 'VIEW' then 'view' 101 | else t.table_type 102 | end) as table_type, 103 | c.column_name, 104 | c.column_type, 105 | c.column_default, 106 | c.column_key, 107 | c.is_nullable, 108 | c.extra, 109 | c.column_comment 110 | from information_schema.tables as t 111 | inner join information_schema.columns as c 112 | on t.table_name = c.table_name 113 | and t.table_schema = c.table_schema 114 | where t.table_type in('base table', 'view') 115 | and t.table_schema = '{$this->dbName}' 116 | and t.table_name = '{$table->name}' 117 | order by t.table_schema, t.table_name, c.ordinal_position"; 118 | 119 | $columnInfos = DB::select($columnSql); 120 | foreach ($columnInfos as $columnInfo) { 121 | $columnBuilder = $table->columns()->withTrashed()->where('name', $columnInfo->column_name); 122 | if ($columnBuilder->exists()) { 123 | $column = $columnBuilder->first(); 124 | if ($column->trashed()) { 125 | $column->restore(); 126 | } 127 | $table->columns()->where('name', $columnInfo->column_name)->update([ 128 | 'name' => $columnInfo->column_name, 129 | 'type' => $columnInfo->column_type, 130 | 'default' => $columnInfo->column_default, 131 | 'key' => $columnInfo->column_key, 132 | 'is_nullable' => $columnInfo->is_nullable == 'YES' ? true : false, 133 | 'extra' => $columnInfo->extra, 134 | 'comment' => $columnInfo->column_comment, 135 | ]); 136 | } else { 137 | $table->columns()->create([ 138 | 'name' => $columnInfo->column_name, 139 | 'type' => $columnInfo->column_type, 140 | 'default' => $columnInfo->column_default, 141 | 'key' => $columnInfo->column_key, 142 | 'is_nullable' => $columnInfo->is_nullable == 'YES' ? true : false, 143 | 'extra' => $columnInfo->extra, 144 | 'comment' => $columnInfo->column_comment, 145 | ]); 146 | } 147 | } 148 | 149 | $columnNames = array_pluck($columnInfos, 'column_name'); 150 | 151 | $table->columns()->whereNotIn('name', $columnNames)->delete(); 152 | $bar->advance(); 153 | } 154 | $bar->finish(); 155 | } 156 | } -------------------------------------------------------------------------------- /src/Controllers/DictController.php: -------------------------------------------------------------------------------- 1 | get(); 18 | 19 | $tableId = Request::has('table_id') ? Request::input('table_id') : ( $tables->first() ? $tables->first()->id : 0 ); 20 | /** @var DbTable $currentTable */ 21 | $currentTable = DbTable::find($tableId); 22 | // Get All Columns By TableId 23 | $columns = $currentTable ? $currentTable->columns : []; 24 | 25 | return view('LarevelDbDict::index')->withTables($tables)->withColumns($columns)->withCurrentTable($currentTable); 26 | } 27 | 28 | public function updateColumn($column_id) 29 | { 30 | /** @var DbColumn $column */ 31 | $column = DbColumn::find($column_id); 32 | 33 | if (empty($column)) { 34 | return []; 35 | } 36 | 37 | $column->update([ 'description' => Request::input('description') ]); 38 | 39 | return $column; 40 | } 41 | 42 | public function updateTable($table_id) 43 | { 44 | /** @var DbTable $table */ 45 | $table = DbTable::find($table_id); 46 | 47 | if (empty($table)) { 48 | return []; 49 | } 50 | 51 | $table->update([ 'description' => Request::input('description') ]); 52 | 53 | return $table; 54 | } 55 | 56 | public function postDictSync() 57 | { 58 | \Artisan::call('db:dict-sync'); 59 | 60 | return [ 61 | 'success' => true 62 | ]; 63 | } 64 | } -------------------------------------------------------------------------------- /src/LavavelDbDictProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__.'/../views', 'LarevelDbDict'); 18 | 19 | $this->publishes([ 20 | __DIR__.'/../database/migrations/' => database_path('migrations') 21 | ], 'migrations'); 22 | 23 | $this->commands([ SyncCommand::class ]); 24 | 25 | if ( ! $this->app->routesAreCached()) { 26 | require __DIR__.'/routes.php'; 27 | } 28 | } 29 | 30 | /** 31 | * Register the service provider. 32 | * 33 | * @return void 34 | */ 35 | public function register() 36 | { 37 | } 38 | 39 | /** 40 | * Get the services provided by the provider. 41 | * 42 | * @return array 43 | */ 44 | public function provides() 45 | { 46 | return [ 'command.laravel-db-dict.sync' ]; 47 | } 48 | } -------------------------------------------------------------------------------- /src/Models/DbCategory.php: -------------------------------------------------------------------------------- 1 | hasMany(DbTable::class); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Models/DbColumn.php: -------------------------------------------------------------------------------- 1 | 'boolean' 27 | ]; 28 | 29 | protected $dates = [ 30 | 'deleted_at' 31 | ]; 32 | 33 | public function table() 34 | { 35 | return $this->belongsTo(DbTable::class); 36 | } 37 | 38 | public function getIsNullableAttribute($value) 39 | { 40 | return $value ? 'YES' : 'NO'; 41 | } 42 | 43 | public function getKeyAttribute($value) 44 | { 45 | 46 | return $value ? $value : ''; 47 | } 48 | } -------------------------------------------------------------------------------- /src/Models/DbTable.php: -------------------------------------------------------------------------------- 1 | 'boolean' 22 | ]; 23 | 24 | protected $dates = [ 25 | 'deleted_at' 26 | ]; 27 | 28 | public function category() 29 | { 30 | return $this->belongsTo(DbCategory::class); 31 | } 32 | 33 | public function columns() 34 | { 35 | return $this->hasMany(DbColumn::class, 'table_id'); 36 | } 37 | } -------------------------------------------------------------------------------- /src/routes.php: -------------------------------------------------------------------------------- 1 | 'laravel-db-dict', 7 | ], function () { 8 | Route::get('/', [ 9 | 'uses' => DictController::class.'@index', 10 | 'as' => 'db-dict::index' 11 | ]); 12 | Route::put('column/{id}', [ 13 | 'uses' => DictController::class.'@updateColumn', 14 | 'as' => 'db-dict::column.update' 15 | ]); 16 | Route::put('table/{id}', [ 17 | 'uses' => DictController::class.'@updateTable', 18 | 'as' => 'db-dict::table.update' 19 | ]); 20 | Route::post('db-dict-sync', [ 21 | 'uses' => DictController::class.'@postDictSync', 22 | 'as' => 'db-dict::db-dict-sync' 23 | ]); 24 | }); -------------------------------------------------------------------------------- /views/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Laravel DB dict 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 21 | 76 | 77 | 78 |
79 |
80 | 94 | 95 |
96 | @if ($columns === null) 97 |
98 | Log file >50M, please download it. 99 |
100 | @else 101 |
102 |

{{ $current_table->name }} 103 | 104 | 107 | 110 | 111 |

112 |
113 |
114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | @foreach($columns as $column) 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 143 | 144 | 145 | @endforeach 146 | 147 | 148 |
字段名类型默认值索引是否为空其他字段备注描述
{{ $column->name }}{{ $column->type }}{{ $column->default }}{{ $column->key }}{!! $column->is_nullable !!}{{ $column->extra }}{{ $column->comment }} 139 | 142 |
149 | @endif 150 |
151 |
152 |
153 |
154 |
155 | 156 | 157 | 158 | 159 | 161 | 208 | 209 | --------------------------------------------------------------------------------