├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── resources └── views │ ├── artisan.blade.php │ ├── database.blade.php │ └── scaffold.blade.php └── src ├── Controllers ├── RouteController.php ├── ScaffoldController.php └── TerminalController.php ├── Helpers.php ├── HelpersServiceProvider.php └── Scaffold ├── ControllerCreator.php ├── MigrationCreator.php ├── ModelCreator.php └── stubs ├── controller.stub ├── create.stub └── model.stub /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | phpunit.phar 3 | /vendor 4 | composer.phar 5 | composer.lock 6 | *.project 7 | .idea/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jens Segers 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Helpers for laravel-admin 2 | ========================= 3 | 4 | [![StyleCI](https://styleci.io/repos/97900966/shield?branch=master)](https://styleci.io/repos/97900966) 5 | [![Packagist](https://img.shields.io/packagist/l/laravel-admin-ext/helpers.svg?maxAge=2592000)](https://packagist.org/packages/laravel-admin-ext/helpers) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/laravel-admin-ext/helpers.svg?style=flat-square)](https://packagist.org/packages/laravel-admin-ext/helpers) 7 | [![Pull request welcome](https://img.shields.io/badge/pr-welcome-green.svg?style=flat-square)]() 8 | 9 | [Documentation](http://laravel-admin.org/docs/#/en/extension-helpers) | [中文文档](http://laravel-admin.org/docs/#/zh/extension-helpers) 10 | 11 | DEMO [helpers](http://demo.laravel-admin.org/helpers/scaffold) 12 | 13 | Login using `admin/admin` 14 | 15 | ## Installation 16 | 17 | ``` 18 | // For laravel-admin 1.x 19 | $ composer require "laravel-admin-ext/helpers:1.*" 20 | 21 | // For laravel-admin 2.x 22 | $ composer require "laravel-admin-ext/helpers:2.*" 23 | ``` 24 | 25 | Import menu items. 26 | 27 | ```shell 28 | $ php artisan admin:import helpers 29 | ``` 30 | 31 | ## Usage 32 | 33 | See [wiki](http://laravel-admin.org/docs/#/en/extension-helpers?id=helpers) 34 | 35 | ## Donate 36 | 37 | > Help keeping the project development going, by donating a little. Thanks in advance. 38 | 39 | [![PayPal Me](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/zousong) 40 | 41 | ![-1](https://cloud.githubusercontent.com/assets/1479100/23287423/45c68202-fa78-11e6-8125-3e365101a313.jpg) 42 | 43 | License 44 | ------------ 45 | Licensed under [The MIT License (MIT)](LICENSE). 46 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-admin-ext/helpers", 3 | "description": "Helpers extension for laravel-admin", 4 | "type": "library", 5 | "keywords": ["laravel-admin", "helpers"], 6 | "homepage": "https://github.com/laravel-admin-extensions/helpers", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "z-song", 11 | "email": "zosong@126.com" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=7.0.0", 16 | "encore/laravel-admin": "~1.6" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit": "~6.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "Encore\\Admin\\Helpers\\": "src/" 24 | } 25 | }, 26 | "extra": { 27 | "laravel": { 28 | "providers": [ 29 | "Encore\\Admin\\Helpers\\HelpersServiceProvider" 30 | ] 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/views/artisan.blade.php: -------------------------------------------------------------------------------- 1 | 119 | 120 |
121 |
122 | 123 |
124 |
125 | 126 | 127 | 128 |
129 | 130 | 172 |
173 | -------------------------------------------------------------------------------- /resources/views/database.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 113 | 114 |
115 |
116 | 117 | 118 |
119 | 120 |
121 | 122 | 141 |
142 | 143 |
144 |
145 |
146 | 147 | 148 | 149 |
150 | 151 | 165 |
166 | -------------------------------------------------------------------------------- /resources/views/scaffold.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Scaffold

4 |
5 | 6 |
7 | 8 |
9 | 10 |
11 | 12 |
13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 | 23 |   Table name can't be empty! 24 | 25 | 26 |
27 |
28 | 29 | 30 |
31 | 32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 | 40 |
41 |
42 | 43 |
44 |
45 |
46 | 49 | 52 | 55 | 58 |
59 |
60 |
61 | 62 |
63 | 64 |
65 | 66 |

Fields

67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | @if(old('fields')) 81 | @foreach(old('fields') as $index => $field) 82 | 83 | 86 | 93 | 94 | 102 | 103 | 104 | 105 | 106 | @endforeach 107 | @else 108 | 109 | 112 | 119 | 120 | 128 | 129 | 130 | 131 | 132 | @endif 133 | 134 |
Field nameTypeNullableKeyDefault valueCommentAction
84 | 85 | 87 | 92 | 95 | 101 | remove
110 | 111 | 113 | 118 | 121 | 127 | remove
135 | 136 |
137 | 138 |
139 | 140 | 141 |
142 | 143 |
144 | 145 |
146 |
147 | 150 |    151 | 154 | 155 |
156 |
157 | 158 |
159 | 160 | 161 |
162 | 163 |
164 | 165 | {{--
--}} 166 | 167 | {{--

Relations

--}} 168 | 169 | {{----}} 170 | {{----}} 171 | {{----}} 172 | {{----}} 173 | {{----}} 174 | {{----}} 175 | {{----}} 176 | {{----}} 177 | {{----}} 178 | {{----}} 179 | {{----}} 180 | {{----}} 181 | {{--
Relation nameTypeRelated modelforignKeyOtherKeyWith PivotAction
--}} 182 | 183 | {{--
--}} 184 | 185 | {{--
--}} 186 | 187 | {{--
--}} 188 | {{----}} 189 | {{--
--}} 190 | 191 | {{--
--}} 192 | 193 |
194 | 195 | 198 | 199 | {{ csrf_field() }} 200 | 201 | 202 |
203 | 204 |
205 | 206 |
207 | 208 | 233 | 234 | 252 | 253 | -------------------------------------------------------------------------------- /src/Controllers/RouteController.php: -------------------------------------------------------------------------------- 1 | getModel()->setRoutes($this->getRoutes()); 20 | 21 | $content->body(Admin::grid($model, function (Grid $grid) { 22 | $colors = [ 23 | 'GET' => 'green', 24 | 'HEAD' => 'gray', 25 | 'POST' => 'blue', 26 | 'PUT' => 'yellow', 27 | 'DELETE' => 'red', 28 | 'PATCH' => 'aqua', 29 | 'OPTIONS'=> 'light-blue', 30 | ]; 31 | 32 | $grid->method()->map(function ($method) use ($colors) { 33 | return "$method"; 34 | })->implode(' '); 35 | 36 | $grid->uri()->display(function ($uri) { 37 | return preg_replace('/\{.+?\}/', '$0', $uri); 38 | })->sortable(); 39 | 40 | $grid->name(); 41 | 42 | $grid->action()->display(function ($uri) { 43 | return preg_replace('/@.+/', '$0', $uri); 44 | }); 45 | $grid->middleware()->badge('yellow'); 46 | 47 | $grid->disablePagination(); 48 | $grid->disableRowSelector(); 49 | $grid->disableActions(); 50 | $grid->disableCreation(); 51 | $grid->disableExport(); 52 | 53 | $grid->filter(function ($filter) { 54 | $filter->disableIdFilter(); 55 | $filter->equal('action'); 56 | $filter->equal('uri'); 57 | }); 58 | })); 59 | }); 60 | } 61 | 62 | protected function getModel() 63 | { 64 | return new class() extends Model { 65 | protected $routes; 66 | 67 | protected $where = []; 68 | 69 | public function setRoutes($routes) 70 | { 71 | $this->routes = $routes; 72 | 73 | return $this; 74 | } 75 | 76 | public function where($column, $condition) 77 | { 78 | $this->where[$column] = trim($condition); 79 | 80 | return $this; 81 | } 82 | 83 | public function orderBy() 84 | { 85 | return $this; 86 | } 87 | 88 | public function get() 89 | { 90 | $this->routes = collect($this->routes)->filter(function ($route) { 91 | foreach ($this->where as $column => $condition) { 92 | if (!Str::contains($route[$column], $condition)) { 93 | return false; 94 | } 95 | } 96 | 97 | return true; 98 | })->all(); 99 | 100 | $instance = $this->newModelInstance(); 101 | 102 | return $instance->newCollection(array_map(function ($item) use ($instance) { 103 | return $instance->newFromBuilder($item); 104 | }, $this->routes)); 105 | } 106 | }; 107 | } 108 | 109 | public function getRoutes() 110 | { 111 | $routes = app('router')->getRoutes(); 112 | 113 | $routes = collect($routes)->map(function ($route) { 114 | return $this->getRouteInformation($route); 115 | })->all(); 116 | 117 | if ($sort = request('_sort')) { 118 | $routes = $this->sortRoutes($sort, $routes); 119 | } 120 | 121 | return array_filter($routes); 122 | } 123 | 124 | /** 125 | * Get the route information for a given route. 126 | * 127 | * @param \Illuminate\Routing\Route $route 128 | * 129 | * @return array 130 | */ 131 | protected function getRouteInformation(Route $route) 132 | { 133 | return [ 134 | 'host' => $route->domain(), 135 | 'method' => $route->methods(), 136 | 'uri' => $route->uri(), 137 | 'name' => $route->getName(), 138 | 'action' => $route->getActionName(), 139 | 'middleware' => $this->getRouteMiddleware($route), 140 | ]; 141 | } 142 | 143 | /** 144 | * Sort the routes by a given element. 145 | * 146 | * @param string $sort 147 | * @param array $routes 148 | * 149 | * @return array 150 | */ 151 | protected function sortRoutes($sort, $routes) 152 | { 153 | return Arr::sort($routes, function ($route) use ($sort) { 154 | return $route[$sort]; 155 | }); 156 | } 157 | 158 | /** 159 | * Get before filters. 160 | * 161 | * @param \Illuminate\Routing\Route $route 162 | * 163 | * @return string 164 | */ 165 | protected function getRouteMiddleware($route) 166 | { 167 | return collect($route->gatherMiddleware())->map(function ($middleware) { 168 | return $middleware instanceof \Closure ? 'Closure' : $middleware; 169 | }); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/Controllers/ScaffoldController.php: -------------------------------------------------------------------------------- 1 | header('Scaffold'); 22 | 23 | $dbTypes = [ 24 | 'string', 'integer', 'text', 'float', 'double', 'decimal', 'boolean', 'date', 'time', 25 | 'dateTime', 'timestamp', 'char', 'mediumText', 'longText', 'tinyInteger', 'smallInteger', 26 | 'mediumInteger', 'bigInteger', 'unsignedTinyInteger', 'unsignedSmallInteger', 'unsignedMediumInteger', 27 | 'unsignedInteger', 'unsignedBigInteger', 'enum', 'json', 'jsonb', 'dateTimeTz', 'timeTz', 28 | 'timestampTz', 'nullableTimestamps', 'binary', 'ipAddress', 'macAddress', 29 | ]; 30 | 31 | $action = URL::current(); 32 | 33 | $content->row(view('laravel-admin-helpers::scaffold', compact('dbTypes', 'action'))); 34 | }); 35 | } 36 | 37 | public function store(Request $request) 38 | { 39 | $paths = []; 40 | $message = ''; 41 | 42 | try { 43 | 44 | // 1. Create model. 45 | if (in_array('model', $request->get('create'))) { 46 | $modelCreator = new ModelCreator($request->get('table_name'), $request->get('model_name')); 47 | 48 | $paths['model'] = $modelCreator->create( 49 | $request->get('primary_key'), 50 | $request->get('timestamps') == 'on', 51 | $request->get('soft_deletes') == 'on' 52 | ); 53 | } 54 | 55 | // 2. Create controller. 56 | if (in_array('controller', $request->get('create'))) { 57 | $paths['controller'] = (new ControllerCreator($request->get('controller_name'))) 58 | ->create($request->get('model_name'), $request->get('fields')); 59 | } 60 | 61 | // 3. Create migration. 62 | if (in_array('migration', $request->get('create'))) { 63 | $migrationName = 'create_'.$request->get('table_name').'_table'; 64 | 65 | $paths['migration'] = (new MigrationCreator(app('files')))->buildBluePrint( 66 | $request->get('fields'), 67 | $request->get('primary_key', 'id'), 68 | $request->get('timestamps') == 'on', 69 | $request->get('soft_deletes') == 'on' 70 | )->create($migrationName, database_path('migrations'), $request->get('table_name')); 71 | } 72 | 73 | // 4. Run migrate. 74 | if (in_array('migrate', $request->get('create'))) { 75 | Artisan::call('migrate'); 76 | $message = Artisan::output(); 77 | } 78 | } catch (\Exception $exception) { 79 | 80 | // Delete generated files if exception thrown. 81 | app('files')->delete($paths); 82 | 83 | return $this->backWithException($exception); 84 | } 85 | 86 | return $this->backWithSuccess($paths, $message); 87 | } 88 | 89 | protected function backWithException(\Exception $exception) 90 | { 91 | $error = new MessageBag([ 92 | 'title' => 'Error', 93 | 'message' => $exception->getMessage(), 94 | ]); 95 | 96 | return back()->withInput()->with(compact('error')); 97 | } 98 | 99 | protected function backWithSuccess($paths, $message) 100 | { 101 | $messages = []; 102 | 103 | foreach ($paths as $name => $path) { 104 | $messages[] = ucfirst($name).": $path"; 105 | } 106 | 107 | $messages[] = "
$message"; 108 | 109 | $success = new MessageBag([ 110 | 'title' => 'Success', 111 | 'message' => implode('
', $messages), 112 | ]); 113 | 114 | return back()->with(compact('success')); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Controllers/TerminalController.php: -------------------------------------------------------------------------------- 1 | header('Artisan terminal'); 27 | 28 | $content->row(view('laravel-admin-helpers::artisan', ['commands' => $this->organizedCommands()])); 29 | }); 30 | } 31 | 32 | public function runArtisan() 33 | { 34 | $command = Request::get('c', 'list'); 35 | 36 | // If Exception raised. 37 | if (1 === Artisan::handle( 38 | new ArgvInput(explode(' ', 'artisan '.trim($command))), 39 | $output = new StringOutput() 40 | )) { 41 | return $this->renderException(new Exception($output->getContent())); 42 | } 43 | 44 | return sprintf('
%s
', $output->getContent()); 45 | } 46 | 47 | public function database() 48 | { 49 | return Admin::content(function (Content $content) { 50 | $content->header('Database terminal'); 51 | 52 | $content->row(view('laravel-admin-helpers::database', ['connections' => $this->connections()])); 53 | }); 54 | } 55 | 56 | public function runDatabase() 57 | { 58 | $query = Request::get('q'); 59 | 60 | $connection = Request::get('c', config('database.default')); 61 | 62 | return $this->dispatchQuery($connection, $query); 63 | } 64 | 65 | protected function getDumpedHtml($var) 66 | { 67 | ob_start(); 68 | 69 | dump($var); 70 | 71 | $content = ob_get_contents(); 72 | 73 | ob_get_clean(); 74 | 75 | return substr($content, strpos($content, '
 $_) {
 83 |             $dbs[] = [
 84 |                 'option'   => $name,
 85 |                 'value'    => "db:$name",
 86 |                 'selected' => $name == config('database.default'),
 87 |             ];
 88 |         }
 89 | 
 90 |         $connections = array_filter(config('database.redis'), function ($config) {
 91 |             return is_array($config);
 92 |         });
 93 | 
 94 |         foreach ($connections as $name => $_) {
 95 |             $redis[] = [
 96 |                 'value'     => "redis:$name",
 97 |                 'option'    => $name,
 98 |             ];
 99 |         }
100 | 
101 |         return compact('dbs', 'redis');
102 |     }
103 | 
104 |     protected function table(array $headers, $rows, $style = 'default')
105 |     {
106 |         $output = new StringOutput();
107 | 
108 |         $table = new Table($output);
109 | 
110 |         if ($rows instanceof Arrayable) {
111 |             $rows = $rows->toArray();
112 |         }
113 | 
114 |         $table->setHeaders($headers)->setRows($rows)->setStyle($style)->render();
115 | 
116 |         return $output->getContent();
117 |     }
118 | 
119 |     protected function dispatchQuery($connection, $query)
120 |     {
121 |         list($type, $connection) = explode(':', $connection);
122 | 
123 |         if ($type == 'redis') {
124 |             return $this->execRedisCommand($connection, $query);
125 |         }
126 | 
127 |         $config = config('database.connections.'.$connection);
128 | 
129 |         if ($config['driver'] == 'mongodb') {
130 |             return $this->execMongodbQuery($config, $query);
131 |         }
132 | 
133 |         /* @var \Illuminate\Database\Connection $connection */
134 |         $connection = DB::connection($connection);
135 | 
136 |         $connection->enableQueryLog();
137 | 
138 |         try {
139 |             $result = $connection->select(str_replace([';', "\G"], '', $query));
140 |         } catch (Exception $exception) {
141 |             return $this->renderException($exception);
142 |         }
143 | 
144 |         $log = current($connection->getQueryLog());
145 | 
146 |         if (empty($result)) {
147 |             return sprintf("
Empty set (%s sec)
\r\n", number_format($log['time'] / 1000, 2)); 148 | } 149 | 150 | $result = json_decode(json_encode($result), true); 151 | 152 | if (Str::contains($query, "\G")) { 153 | return $this->getDumpedHtml($result); 154 | } 155 | 156 | return sprintf( 157 | "
%s \n%d %s in set (%s sec)
\r\n", 158 | $this->table(array_keys(current($result)), $result), 159 | count($result), 160 | count($result) == 1 ? 'row' : 'rows', 161 | number_format($log['time'] / 1000, 2) 162 | ); 163 | } 164 | 165 | protected function execMongodbQuery($config, $query) 166 | { 167 | if (Str::contains($query, '.find(') && !Str::contains($query, '.toArray(')) { 168 | $query .= '.toArray()'; 169 | } 170 | 171 | $manager = new Manager("mongodb://{$config['host']}:{$config['port']}"); 172 | $command = new Command(['eval' => $query]); 173 | 174 | try { 175 | $cursor = $manager->executeCommand($config['database'], $command); 176 | } catch (Exception $exception) { 177 | return $this->renderException($exception); 178 | } 179 | 180 | $result = $cursor->toArray()[0]; 181 | 182 | $result = json_decode(json_encode($result), true); 183 | 184 | if (isset($result['errmsg'])) { 185 | return $this->renderException(new Exception($result['errmsg'])); 186 | } 187 | 188 | return $this->getDumpedHtml($result['retval']); 189 | } 190 | 191 | protected function execRedisCommand($connection, $command) 192 | { 193 | $command = explode(' ', $command); 194 | 195 | try { 196 | $result = Redis::connection($connection)->executeRaw($command); 197 | } catch (Exception $exception) { 198 | return $this->renderException($exception); 199 | } 200 | 201 | if (is_string($result) && Str::startsWith($result, ['ERR ', 'WRONGTYPE '])) { 202 | return $this->renderException(new Exception($result)); 203 | } 204 | 205 | return $this->getDumpedHtml($result); 206 | } 207 | 208 | protected function organizedCommands() 209 | { 210 | $commands = array_keys(Artisan::all()); 211 | 212 | $groups = $others = []; 213 | 214 | foreach ($commands as $command) { 215 | $parts = explode(':', $command); 216 | 217 | if (isset($parts[1])) { 218 | $groups[$parts[0]][] = $command; 219 | } else { 220 | $others[] = $command; 221 | } 222 | } 223 | 224 | foreach ($groups as $key => $group) { 225 | if (count($group) === 1) { 226 | $others[] = $group[0]; 227 | 228 | unset($groups[$key]); 229 | } 230 | } 231 | 232 | ksort($groups); 233 | sort($others); 234 | 235 | return compact('groups', 'others'); 236 | } 237 | 238 | protected function renderException(Exception $exception) 239 | { 240 | return sprintf( 241 | "
   %s
", 242 | str_replace("\n", '
', $exception->getMessage()) 243 | ); 244 | } 245 | } 246 | 247 | class StringOutput extends Output 248 | { 249 | public $output = ''; 250 | 251 | public function clear() 252 | { 253 | $this->output = ''; 254 | } 255 | 256 | protected function doWrite($message, $newline) 257 | { 258 | $this->output .= $message.($newline ? "\n" : ''); 259 | } 260 | 261 | public function getContent() 262 | { 263 | return trim($this->output); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/Helpers.php: -------------------------------------------------------------------------------- 1 | get('helpers/terminal/database', 'Encore\Admin\Helpers\Controllers\TerminalController@database'); 33 | $router->post('helpers/terminal/database', 'Encore\Admin\Helpers\Controllers\TerminalController@runDatabase'); 34 | $router->get('helpers/terminal/artisan', 'Encore\Admin\Helpers\Controllers\TerminalController@artisan'); 35 | $router->post('helpers/terminal/artisan', 'Encore\Admin\Helpers\Controllers\TerminalController@runArtisan'); 36 | $router->get('helpers/scaffold', 'Encore\Admin\Helpers\Controllers\ScaffoldController@index'); 37 | $router->post('helpers/scaffold', 'Encore\Admin\Helpers\Controllers\ScaffoldController@store'); 38 | $router->get('helpers/routes', 'Encore\Admin\Helpers\Controllers\RouteController@index'); 39 | }); 40 | } 41 | 42 | public static function import() 43 | { 44 | $lastOrder = Menu::max('order') ?: 0; 45 | 46 | $root = [ 47 | 'parent_id' => 0, 48 | 'order' => $lastOrder++, 49 | 'title' => 'Helpers', 50 | 'icon' => 'fa-gears', 51 | 'uri' => '', 52 | ]; 53 | 54 | $root = Menu::create($root); 55 | 56 | $menus = [ 57 | [ 58 | 'title' => 'Scaffold', 59 | 'icon' => 'fa-keyboard-o', 60 | 'uri' => 'helpers/scaffold', 61 | ], 62 | [ 63 | 'title' => 'Database terminal', 64 | 'icon' => 'fa-database', 65 | 'uri' => 'helpers/terminal/database', 66 | ], 67 | [ 68 | 'title' => 'Laravel artisan', 69 | 'icon' => 'fa-terminal', 70 | 'uri' => 'helpers/terminal/artisan', 71 | ], 72 | [ 73 | 'title' => 'Routes', 74 | 'icon' => 'fa-list-alt', 75 | 'uri' => 'helpers/routes', 76 | ], 77 | ]; 78 | 79 | foreach ($menus as $menu) { 80 | $menu['parent_id'] = $root->id; 81 | $menu['order'] = $lastOrder++; 82 | 83 | Menu::create($menu); 84 | } 85 | 86 | parent::createPermission('Admin helpers', 'ext.helpers', 'helpers/*'); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/HelpersServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__.'/../resources/views', 'laravel-admin-helpers'); 15 | 16 | Helpers::boot(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Scaffold/ControllerCreator.php: -------------------------------------------------------------------------------- 1 | name = $name; 36 | 37 | $this->files = $files ?: app('files'); 38 | } 39 | 40 | /** 41 | * Create a controller. 42 | * 43 | * @param string $model 44 | * 45 | * @throws \Exception 46 | * 47 | * @return string 48 | */ 49 | public function create($model, $fields) 50 | { 51 | $path = $this->getpath($this->name); 52 | 53 | if ($this->files->exists($path)) { 54 | throw new \Exception("Controller [$this->name] already exists!"); 55 | } 56 | 57 | $this->generateGridField($fields); 58 | 59 | $this->generateShowField($fields); 60 | 61 | $this->generateFormField($fields); 62 | 63 | $stub = $this->files->get($this->getStub()); 64 | 65 | $this->files->put($path, $this->replace($stub, $this->name, $model)); 66 | 67 | return $path; 68 | } 69 | 70 | /** 71 | * @param string $stub 72 | * @param string $name 73 | * @param string $model 74 | * 75 | * @return string 76 | */ 77 | protected function replace($stub, $name, $model) 78 | { 79 | $stub = $this->replaceClass($stub, $name); 80 | 81 | return str_replace( 82 | ['DummyModelNamespace', 'DummyModel', 'DummyGridField', 'DummyShowField', 'DummyFormField'], 83 | [$model, class_basename($model), $this->DummyGridField, $this->DummyShowField, $this->DummyFormField], 84 | $stub 85 | ); 86 | } 87 | 88 | /** 89 | * Get controller namespace from giving name. 90 | * 91 | * @param string $name 92 | * 93 | * @return string 94 | */ 95 | protected function getNamespace($name) 96 | { 97 | return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); 98 | } 99 | 100 | /** 101 | * Replace the class name for the given stub. 102 | * 103 | * @param string $stub 104 | * @param string $name 105 | * 106 | * @return string 107 | */ 108 | protected function replaceClass($stub, $name) 109 | { 110 | $class = str_replace($this->getNamespace($name).'\\', '', $name); 111 | 112 | return str_replace(['DummyClass', 'DummyNamespace'], [$class, $this->getNamespace($name)], $stub); 113 | } 114 | 115 | /** 116 | * Get file path from giving controller name. 117 | * 118 | * @param $name 119 | * 120 | * @return string 121 | */ 122 | public function getPath($name) 123 | { 124 | $segments = explode('\\', $name); 125 | 126 | array_shift($segments); 127 | 128 | return app_path(implode('/', $segments)).'.php'; 129 | } 130 | 131 | /** 132 | * Get stub file path. 133 | * 134 | * @return string 135 | */ 136 | public function getStub() 137 | { 138 | return __DIR__.'/stubs/controller.stub'; 139 | } 140 | 141 | public function generateFormField($fields = []) 142 | { 143 | $fields = array_filter($fields, function ($field) { 144 | return isset($field['name']) && !empty($field['name']); 145 | }); 146 | 147 | if (empty($fields)) { 148 | throw new \Exception('Table fields can\'t be empty'); 149 | } 150 | 151 | foreach ($fields as $field) { 152 | $rows[] = "\$form->text('{$field['name']}', '{$field['name']}');\n"; 153 | } 154 | 155 | $this->DummyFormField = trim(implode(str_repeat(' ', 8), $rows), "\n"); 156 | 157 | return $this; 158 | } 159 | 160 | public function generateShowField($fields = []) 161 | { 162 | $fields = array_filter($fields, function ($field) { 163 | return isset($field['name']) && !empty($field['name']); 164 | }); 165 | 166 | if (empty($fields)) { 167 | throw new \Exception('Table fields can\'t be empty'); 168 | } 169 | foreach ($fields as $field) { 170 | $rows[] = "\$show->{$field['name']}('{$field['name']}');\n"; 171 | } 172 | 173 | $this->DummyShowField = trim(implode(str_repeat(' ', 8), $rows), "\n"); 174 | 175 | return $this; 176 | } 177 | 178 | public function generateGridField($fields = []) 179 | { 180 | $fields = array_filter($fields, function ($field) { 181 | return isset($field['name']) && !empty($field['name']); 182 | }); 183 | 184 | if (empty($fields)) { 185 | throw new \Exception('Table fields can\'t be empty'); 186 | } 187 | foreach ($fields as $field) { 188 | $rows[] = "\$grid->{$field['name']}('{$field['name']}');\n"; 189 | } 190 | 191 | $this->DummyGridField = trim(implode(str_repeat(' ', 8), $rows), "\n"); 192 | 193 | return $this; 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/Scaffold/MigrationCreator.php: -------------------------------------------------------------------------------- 1 | ensureMigrationDoesntAlreadyExist($name); 34 | 35 | $path = $this->getPath($name, $path); 36 | 37 | $stub = $this->files->get(__DIR__.'/stubs/create.stub'); 38 | 39 | $this->files->put($path, $this->populateStub($name, $stub, $table)); 40 | 41 | $this->firePostCreateHooks($table); 42 | 43 | return $path; 44 | } 45 | 46 | /** 47 | * Populate stub. 48 | * 49 | * @param string $name 50 | * @param string $stub 51 | * @param string $table 52 | * 53 | * @return mixed 54 | */ 55 | protected function populateStub($name, $stub, $table) 56 | { 57 | return str_replace( 58 | ['DummyClass', 'DummyTable', 'DummyStructure'], 59 | [$this->getClassName($name), $table, $this->bluePrint], 60 | $stub 61 | ); 62 | } 63 | 64 | /** 65 | * Build the table blueprint. 66 | * 67 | * @param array $fields 68 | * @param string $keyName 69 | * @param bool|true $useTimestamps 70 | * @param bool|false $softDeletes 71 | * 72 | * @throws \Exception 73 | * 74 | * @return $this 75 | */ 76 | public function buildBluePrint($fields = [], $keyName = 'id', $useTimestamps = true, $softDeletes = false) 77 | { 78 | $fields = array_filter($fields, function ($field) { 79 | return isset($field['name']) && !empty($field['name']); 80 | }); 81 | 82 | if (empty($fields)) { 83 | throw new \Exception('Table fields can\'t be empty'); 84 | } 85 | 86 | $rows[] = "\$table->increments('$keyName');\n"; 87 | 88 | foreach ($fields as $field) { 89 | $column = "\$table->{$field['type']}('{$field['name']}')"; 90 | 91 | if ($field['key']) { 92 | $column .= "->{$field['key']}()"; 93 | } 94 | 95 | if (isset($field['default']) && $field['default']) { 96 | $column .= "->default('{$field['default']}')"; 97 | } 98 | 99 | if (isset($field['comment']) && $field['comment']) { 100 | $column .= "->comment('{$field['comment']}')"; 101 | } 102 | 103 | if (Arr::get($field, 'nullable') == 'on') { 104 | $column .= '->nullable()'; 105 | } 106 | 107 | $rows[] = $column.";\n"; 108 | } 109 | 110 | if ($useTimestamps) { 111 | $rows[] = "\$table->timestamps();\n"; 112 | } 113 | 114 | if ($softDeletes) { 115 | $rows[] = "\$table->softDeletes();\n"; 116 | } 117 | 118 | $this->bluePrint = trim(implode(str_repeat(' ', 12), $rows), "\n"); 119 | 120 | return $this; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Scaffold/ModelCreator.php: -------------------------------------------------------------------------------- 1 | tableName = $tableName; 40 | 41 | $this->name = $name; 42 | 43 | $this->files = $files ?: app('files'); 44 | } 45 | 46 | /** 47 | * Create a new migration file. 48 | * 49 | * @param string $keyName 50 | * @param bool|true $timestamps 51 | * @param bool|false $softDeletes 52 | * 53 | * @throws \Exception 54 | * 55 | * @return string 56 | */ 57 | public function create($keyName = 'id', $timestamps = true, $softDeletes = false) 58 | { 59 | $path = $this->getpath($this->name); 60 | 61 | if ($this->files->exists($path)) { 62 | throw new \Exception("Model [$this->name] already exists!"); 63 | } 64 | 65 | $stub = $this->files->get($this->getStub()); 66 | 67 | $stub = $this->replaceClass($stub, $this->name) 68 | ->replaceNamespace($stub, $this->name) 69 | ->replaceSoftDeletes($stub, $softDeletes) 70 | ->replaceTable($stub, $this->name) 71 | ->replaceTimestamp($stub, $timestamps) 72 | ->replacePrimaryKey($stub, $keyName) 73 | ->replaceSpace($stub); 74 | 75 | $this->files->put($path, $stub); 76 | 77 | return $path; 78 | } 79 | 80 | /** 81 | * Get path for migration file. 82 | * 83 | * @param string $name 84 | * 85 | * @return string 86 | */ 87 | public function getPath($name) 88 | { 89 | $segments = explode('\\', $name); 90 | 91 | array_shift($segments); 92 | 93 | return app_path(implode('/', $segments)).'.php'; 94 | } 95 | 96 | /** 97 | * Get namespace of giving class full name. 98 | * 99 | * @param string $name 100 | * 101 | * @return string 102 | */ 103 | protected function getNamespace($name) 104 | { 105 | return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); 106 | } 107 | 108 | /** 109 | * Replace class dummy. 110 | * 111 | * @param string $stub 112 | * @param string $name 113 | * 114 | * @return $this 115 | */ 116 | protected function replaceClass(&$stub, $name) 117 | { 118 | $class = str_replace($this->getNamespace($name).'\\', '', $name); 119 | 120 | $stub = str_replace('DummyClass', $class, $stub); 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Replace namespace dummy. 127 | * 128 | * @param string $stub 129 | * @param string $name 130 | * 131 | * @return $this 132 | */ 133 | protected function replaceNamespace(&$stub, $name) 134 | { 135 | $stub = str_replace( 136 | 'DummyNamespace', $this->getNamespace($name), $stub 137 | ); 138 | 139 | return $this; 140 | } 141 | 142 | /** 143 | * Replace soft-deletes dummy. 144 | * 145 | * @param string $stub 146 | * @param bool $softDeletes 147 | * 148 | * @return $this 149 | */ 150 | protected function replaceSoftDeletes(&$stub, $softDeletes) 151 | { 152 | $import = $use = ''; 153 | 154 | if ($softDeletes) { 155 | $import = "use Illuminate\\Database\\Eloquent\\SoftDeletes;\n"; 156 | $use = "use SoftDeletes;\n"; 157 | } 158 | 159 | $stub = str_replace(['DummyImportSoftDeletesTrait', 'DummyUseSoftDeletesTrait'], [$import, $use], $stub); 160 | 161 | return $this; 162 | } 163 | 164 | /** 165 | * Replace primarykey dummy. 166 | * 167 | * @param string $stub 168 | * @param string $keyName 169 | * 170 | * @return $this 171 | */ 172 | protected function replacePrimaryKey(&$stub, $keyName) 173 | { 174 | $modelKey = $keyName == 'id' ? '' : "protected \$primaryKey = '$keyName';\n"; 175 | 176 | $stub = str_replace('DummyModelKey', $modelKey, $stub); 177 | 178 | return $this; 179 | } 180 | 181 | /** 182 | * Replace Table name dummy. 183 | * 184 | * @param string $stub 185 | * @param string $name 186 | * 187 | * @return $this 188 | */ 189 | protected function replaceTable(&$stub, $name) 190 | { 191 | $class = str_replace($this->getNamespace($name).'\\', '', $name); 192 | 193 | $table = Str::plural(strtolower($class)) !== $this->tableName ? "protected \$table = '$this->tableName';\n" : ''; 194 | 195 | $stub = str_replace('DummyModelTable', $table, $stub); 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * Replace timestamps dummy. 202 | * 203 | * @param string $stub 204 | * @param bool $timestamps 205 | * 206 | * @return $this 207 | */ 208 | protected function replaceTimestamp(&$stub, $timestamps) 209 | { 210 | $useTimestamps = $timestamps ? '' : "public \$timestamps = false;\n"; 211 | 212 | $stub = str_replace('DummyTimestamp', $useTimestamps, $stub); 213 | 214 | return $this; 215 | } 216 | 217 | /** 218 | * Replace spaces. 219 | * 220 | * @param string $stub 221 | * 222 | * @return mixed 223 | */ 224 | public function replaceSpace($stub) 225 | { 226 | return str_replace(["\n\n\n", "\n \n"], ["\n\n", ''], $stub); 227 | } 228 | 229 | /** 230 | * Get stub path of model. 231 | * 232 | * @return string 233 | */ 234 | public function getStub() 235 | { 236 | return __DIR__.'/stubs/model.stub'; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/Scaffold/stubs/controller.stub: -------------------------------------------------------------------------------- 1 | header(trans('admin.index')) 27 | ->description(trans('admin.description')) 28 | ->body($this->grid()); 29 | } 30 | 31 | /** 32 | * Show interface. 33 | * 34 | * @param mixed $id 35 | * @param Content $content 36 | * @return Content 37 | */ 38 | public function show($id, Content $content) 39 | { 40 | return $content 41 | ->header(trans('admin.detail')) 42 | ->description(trans('admin.description')) 43 | ->body($this->detail($id)); 44 | } 45 | 46 | /** 47 | * Edit interface. 48 | * 49 | * @param mixed $id 50 | * @param Content $content 51 | * @return Content 52 | */ 53 | public function edit($id, Content $content) 54 | { 55 | return $content 56 | ->header(trans('admin.edit')) 57 | ->description(trans('admin.description')) 58 | ->body($this->form()->edit($id)); 59 | } 60 | 61 | /** 62 | * Create interface. 63 | * 64 | * @param Content $content 65 | * @return Content 66 | */ 67 | public function create(Content $content) 68 | { 69 | return $content 70 | ->header(trans('admin.create')) 71 | ->description(trans('admin.description')) 72 | ->body($this->form()); 73 | } 74 | 75 | /** 76 | * Make a grid builder. 77 | * 78 | * @return Grid 79 | */ 80 | protected function grid() 81 | { 82 | $grid = new Grid(new DummyModel); 83 | 84 | $grid->id('ID'); 85 | DummyGridField 86 | $grid->created_at(trans('admin.created_at')); 87 | $grid->updated_at(trans('admin.updated_at')); 88 | 89 | return $grid; 90 | } 91 | 92 | /** 93 | * Make a show builder. 94 | * 95 | * @param mixed $id 96 | * @return Show 97 | */ 98 | protected function detail($id) 99 | { 100 | $show = new Show(DummyModel::findOrFail($id)); 101 | 102 | $show->id('ID'); 103 | DummyShowField 104 | $show->created_at(trans('admin.created_at')); 105 | $show->updated_at(trans('admin.updated_at')); 106 | 107 | return $show; 108 | } 109 | 110 | /** 111 | * Make a form builder. 112 | * 113 | * @return Form 114 | */ 115 | protected function form() 116 | { 117 | $form = new Form(new DummyModel); 118 | 119 | $form->display('ID'); 120 | DummyFormField 121 | $form->display(trans('admin.created_at')); 122 | $form->display(trans('admin.updated_at')); 123 | 124 | return $form; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Scaffold/stubs/create.stub: -------------------------------------------------------------------------------- 1 |