diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d4b362 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +phpunit.phar +/vendor +composer.phar +composer.lock +*.project +.idea/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..229071a --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015 Jens Segers + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index c063c03..faf6ebb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,37 @@ -# laravel-admin-ext-helpers +Helpers for laravel-admin +========================= +[![StyleCI](https://styleci.io/repos/97900966/shield?branch=master)](https://styleci.io/repos/97900966) +[![Packagist](https://img.shields.io/packagist/l/laravel-admin-ext/helpers.svg?maxAge=2592000)](https://packagist.org/packages/laravel-admin-ext/helpers) +[![Total Downloads](https://img.shields.io/packagist/dt/laravel-admin-ext/helpers.svg?style=flat-square)](https://packagist.org/packages/laravel-admin-ext/helpers) +[![Pull request welcome](https://img.shields.io/badge/pr-welcome-green.svg?style=flat-square)]() + +[Documentation](http://laravel-admin.org/docs/#/en/extension-helpers) | [中文文档](http://laravel-admin.org/docs/#/zh/extension-helpers) + +DEMO [helpers](http://demo.laravel-admin.org/helpers/scaffold) + +Login using `admin/admin` + +## Installation + +``` +$ composer require laravel-admin-ext/helpers + +$ php artisan admin:import helpers +``` + +## Usage + +See [wiki](http://laravel-admin.org/docs/#/en/extension-helpers?id=helpers) + +## Donate + +> Help keeping the project development going, by donating a little. Thanks in advance. + +[![PayPal Me](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/zousong) + +![-1](https://cloud.githubusercontent.com/assets/1479100/23287423/45c68202-fa78-11e6-8125-3e365101a313.jpg) + +License +------------ +Licensed under [The MIT License (MIT)](LICENSE). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4a7e153 --- /dev/null +++ b/composer.json @@ -0,0 +1,34 @@ +{ + "name": "aix/laravel-admin-ext-helpers", + "description": "Helpers extension for laravel-admin", + "version": "1.0.1", + "type": "library", + "keywords": ["laravel-admin", "helpers"], + "homepage": "https://github.com/laravel-admin-extensions/helpers", + "license": "MIT", + "authors": [ + { + "name": "z-song", + "email": "zosong@126.com" + } + ], + "require": { + "php": ">=7.0.0", + "aix/laravel-admin": "1.0.*" + }, + "require-dev": { + "phpunit/phpunit": "~6.0" + }, + "autoload": { + "psr-4": { + "Encore\\Admin\\Helpers\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Encore\\Admin\\Helpers\\HelpersServiceProvider" + ] + } + } +} diff --git a/resources/views/artisan.blade.php b/resources/views/artisan.blade.php new file mode 100644 index 0000000..2a7feb8 --- /dev/null +++ b/resources/views/artisan.blade.php @@ -0,0 +1,173 @@ + + +
+
+ +
+
+ + + +
+ + +
+ \ No newline at end of file diff --git a/resources/views/database.blade.php b/resources/views/database.blade.php new file mode 100644 index 0000000..1de680b --- /dev/null +++ b/resources/views/database.blade.php @@ -0,0 +1,166 @@ + + + +
+
+ + +
+ +
+ + +
+ +
+
+
+ + + +
+ + +
+ \ No newline at end of file diff --git a/resources/views/scaffold.blade.php b/resources/views/scaffold.blade.php new file mode 100644 index 0000000..8dba45c --- /dev/null +++ b/resources/views/scaffold.blade.php @@ -0,0 +1,301 @@ +
+
+

Scaffold

+
+ +
+ +
+ +
+ +
+ +
+ + + +
+ +
+ + +   Table name can't be empty! + + +
+
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+
+
+ + + + +
+
+
+ +
+ +
+ +

Fields

+ + + + + + + + + + + + + + + @if(old('fields')) + @foreach(old('fields') as $index => $field) + + + + + + + + + + + @endforeach + @else + + + + + + + + + + + @endif + +
Field nameTypeSizeNullableKeyDefault valueCommentAction
+ + + + + + remove
+ + + + + + remove
+ +
+ +
+ + +
+ +
+ +
+
+ +    + + +
+
+ +
+ + +
+ +
+ + {{--
--}} + + {{--

Relations

--}} + + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{----}} + {{--
Relation nameTypeRelated modelforignKeyOtherKeyWith PivotAction
--}} + + {{--
--}} + + {{--
--}} + + {{--
--}} + {{----}} + {{--
--}} + + {{--
--}} + +
+ + + + {{ csrf_field() }} + + +
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/src/Controllers/RouteController.php b/src/Controllers/RouteController.php new file mode 100644 index 0000000..d6d7742 --- /dev/null +++ b/src/Controllers/RouteController.php @@ -0,0 +1,171 @@ +getModel()->setRoutes($this->getRoutes()); + + $content->body(Admin::grid($model, function (Grid $grid) { + $colors = [ + 'GET' => 'green', + 'HEAD' => 'gray', + 'POST' => 'blue', + 'PUT' => 'yellow', + 'DELETE' => 'red', + 'PATCH' => 'aqua', + 'OPTIONS'=> 'light-blue', + ]; + + $grid->method()->map(function ($method) use ($colors) { + return "$method"; + })->implode(' '); + + $grid->uri()->display(function ($uri) { + return preg_replace('/\{.+?\}/', '$0', $uri); + })->sortable(); + + $grid->name(); + + $grid->action()->display(function ($uri) { + return preg_replace('/@.+/', '$0', $uri); + }); + $grid->middleware()->badge('yellow'); + + $grid->disablePagination(); + $grid->disableRowSelector(); + $grid->disableActions(); + $grid->disableCreation(); + $grid->disableExport(); + + $grid->filter(function ($filter) { + $filter->disableIdFilter(); + $filter->equal('action'); + $filter->equal('uri'); + }); + })); + }); + } + + protected function getModel() + { + return new class() extends Model { + protected $routes; + + protected $where = []; + + public function setRoutes($routes) + { + $this->routes = $routes; + + return $this; + } + + public function where($column, $condition) + { + $this->where[$column] = trim($condition); + + return $this; + } + + public function orderBy() + { + return $this; + } + + public function get() + { + $this->routes = collect($this->routes)->filter(function ($route) { + foreach ($this->where as $column => $condition) { + if (!Str::contains($route[$column], $condition)) { + return false; + } + } + + return true; + })->all(); + + $instance = $this->newModelInstance(); + + return $instance->newCollection(array_map(function ($item) use ($instance) { + return $instance->newFromBuilder($item); + }, $this->routes)); + } + }; + } + + public function getRoutes() + { + $routes = app('router')->getRoutes(); + + $routes = collect($routes)->map(function ($route) { + return $this->getRouteInformation($route); + })->all(); + + if ($sort = request('_sort')) { + $routes = $this->sortRoutes($sort, $routes); + } + + return array_filter($routes); + } + + /** + * Get the route information for a given route. + * + * @param \Illuminate\Routing\Route $route + * + * @return array + */ + protected function getRouteInformation(Route $route) + { + return [ + 'host' => $route->domain(), + 'method' => $route->methods(), + 'uri' => $route->uri(), + 'name' => $route->getName(), + 'action' => $route->getActionName(), + 'middleware' => $this->getRouteMiddleware($route), + ]; + } + + /** + * Sort the routes by a given element. + * + * @param string $sort + * @param array $routes + * + * @return array + */ + protected function sortRoutes($sort, $routes) + { + return Arr::sort($routes, function ($route) use ($sort) { + return $route[$sort]; + }); + } + + /** + * Get before filters. + * + * @param \Illuminate\Routing\Route $route + * + * @return string + */ + protected function getRouteMiddleware($route) + { + return collect($route->gatherMiddleware())->map(function ($middleware) { + return $middleware instanceof \Closure ? 'Closure' : $middleware; + }); + } +} diff --git a/src/Controllers/ScaffoldController.php b/src/Controllers/ScaffoldController.php new file mode 100644 index 0000000..88d78d9 --- /dev/null +++ b/src/Controllers/ScaffoldController.php @@ -0,0 +1,116 @@ +header('Scaffold'); + + $dbTypes = [ + 'string', 'integer', 'text', 'float', 'double', 'decimal', 'boolean', 'date', 'time', + 'dateTime', 'timestamp', 'char', 'mediumText', 'longText', 'tinyInteger', 'smallInteger', + 'mediumInteger', 'bigInteger', 'unsignedTinyInteger', 'unsignedSmallInteger', 'unsignedMediumInteger', + 'unsignedInteger', 'unsignedBigInteger', 'enum', 'json', 'jsonb', 'dateTimeTz', 'timeTz', + 'timestampTz', 'nullableTimestamps', 'binary', 'ipAddress', 'macAddress', + ]; + + $action = URL::current(); + + $content->row(view('laravel-admin-helpers::scaffold', compact('dbTypes', 'action'))); + }); + } + + public function store(Request $request) + { + $paths = []; + $message = ''; + + try { + + // 1. Create model. + if (in_array('model', $request->get('create'))) { + $modelCreator = new ModelCreator($request->get('table_name'), $request->get('model_name')); + + $paths['model'] = $modelCreator->create( + $request->get('primary_key'), + $request->get('timestamps') == 'on', + $request->get('soft_deletes') == 'on' + ); + } + + // 2. Create controller. + if (in_array('controller', $request->get('create'))) { + $paths['controller'] = (new ControllerCreator($request->get('controller_name'))) + ->create($request->get('model_name')); + } + + // 3. Create migration. + if (in_array('migration', $request->get('create'))) { + $migrationName = 'create_'.$request->get('table_name').'_table'; + + $paths['migration'] = (new MigrationCreator(app('files')))->buildBluePrint( + $request->get('fields'), + $request->get('primary_key', 'id'), + $request->get('timestamps') == 'on', + $request->get('soft_deletes') == 'on' + )->create($migrationName, database_path('migrations'), $request->get('table_name')); + } + + // 4. Run migrate. + if (in_array('migrate', $request->get('create'))) { + Artisan::call('migrate'); + $message = Artisan::output(); + } + } catch (\Exception $exception) { + + // Delete generated files if exception thrown. + app('files')->delete($paths); + + return $this->backWithException($exception); + } + + return $this->backWithSuccess($paths, $message); + } + + protected function backWithException(\Exception $exception) + { + $error = new MessageBag([ + 'title' => 'Error', + 'message' => $exception->getMessage(), + ]); + + return back()->withInput()->with(compact('error')); + } + + protected function backWithSuccess($paths, $message) + { + $messages = []; + + foreach ($paths as $name => $path) { + $messages[] = ucfirst($name).": $path"; + } + + $messages[] = "
$message"; + + $success = new MessageBag([ + 'title' => 'Success', + 'message' => implode('
', $messages), + ]); + + return back()->with(compact('success')); + } +} diff --git a/src/Controllers/TerminalController.php b/src/Controllers/TerminalController.php new file mode 100644 index 0000000..950a829 --- /dev/null +++ b/src/Controllers/TerminalController.php @@ -0,0 +1,265 @@ +header('Artisan terminal'); + + $content->row(view('laravel-admin-helpers::artisan', ['commands' => $this->organizedCommands()])); + }); + } + + public function runArtisan() + { + $command = Request::get('c', 'list'); + + // If Exception raised. + if (1 === Artisan::handle( + new ArgvInput(explode(' ', 'artisan '.trim($command))), + $output = new StringOutput() + )) { + return $this->renderException(new Exception($output->getContent())); + } + + return sprintf('
%s
', $output->getContent()); + } + + public function database() + { + return Admin::content(function (Content $content) { + $content->header('Database terminal'); + + $content->row(view('laravel-admin-helpers::database', ['connections' => $this->connections()])); + }); + } + + public function runDatabase() + { + $query = Request::get('q'); + + $connection = Request::get('c', config('database.default')); + + return $this->dispatchQuery($connection, $query); + } + + protected function getDumpedHtml($var) + { + ob_start(); + + dump($var); + + $content = ob_get_contents(); + + ob_get_clean(); + + return substr($content, strpos($content, '
 $_) {
+            $dbs[] = [
+                'option'   => $name,
+                'value'    => "db:$name",
+                'selected' => $name == config('database.default'),
+            ];
+        }
+
+        $connections = array_filter(config('database.redis'), function ($config) {
+            return is_array($config);
+        });
+
+        foreach ($connections as $name => $_) {
+            $redis[] = [
+                'value'     => "redis:$name",
+                'option'    => $name,
+            ];
+        }
+
+        return compact('dbs', 'redis');
+    }
+
+    protected function table(array $headers, $rows, $style = 'default')
+    {
+        $output = new StringOutput();
+
+        $table = new Table($output);
+
+        if ($rows instanceof Arrayable) {
+            $rows = $rows->toArray();
+        }
+
+        $table->setHeaders($headers)->setRows($rows)->setStyle($style)->render();
+
+        return $output->getContent();
+    }
+
+    protected function dispatchQuery($connection, $query)
+    {
+        list($type, $connection) = explode(':', $connection);
+
+        if ($type == 'redis') {
+            return $this->execRedisCommand($connection, $query);
+        }
+
+        $config = config('database.connections.'.$connection);
+
+        if ($config['driver'] == 'mongodb') {
+            return $this->execMongodbQuery($config, $query);
+        }
+
+        /* @var \Illuminate\Database\Connection $connection */
+        $connection = DB::connection($connection);
+
+        $connection->enableQueryLog();
+
+        try {
+            $result = $connection->select(str_replace([';', "\G"], '', $query));
+        } catch (Exception $exception) {
+            return $this->renderException($exception);
+        }
+
+        $log = current($connection->getQueryLog());
+
+        if (empty($result)) {
+            return sprintf("
Empty set (%s sec)
\r\n", number_format($log['time'] / 1000, 2)); + } + + $result = json_decode(json_encode($result), true); + + if (Str::contains($query, "\G")) { + return $this->getDumpedHtml($result); + } + + return sprintf( + "
%s \n%d %s in set (%s sec)
\r\n", + $this->table(array_keys(current($result)), $result), + count($result), + count($result) == 1 ? 'row' : 'rows', + number_format($log['time'] / 1000, 2) + ); + } + + protected function execMongodbQuery($config, $query) + { + if (Str::contains($query, '.find(') && !Str::contains($query, '.toArray(')) { + $query .= '.toArray()'; + } + + $manager = new Manager("mongodb://{$config['host']}:{$config['port']}"); + $command = new Command(['eval' => $query]); + + try { + $cursor = $manager->executeCommand($config['database'], $command); + } catch (Exception $exception) { + return $this->renderException($exception); + } + + $result = $cursor->toArray()[0]; + + $result = json_decode(json_encode($result), true); + + if (isset($result['errmsg'])) { + return $this->renderException(new Exception($result['errmsg'])); + } + + return $this->getDumpedHtml($result['retval']); + } + + protected function execRedisCommand($connection, $command) + { + $command = explode(' ', $command); + + try { + $result = Redis::connection($connection)->executeRaw($command); + } catch (Exception $exception) { + return $this->renderException($exception); + } + + if (is_string($result) && Str::startsWith($result, ['ERR ', 'WRONGTYPE '])) { + return $this->renderException(new Exception($result)); + } + + return $this->getDumpedHtml($result); + } + + protected function organizedCommands() + { + $commands = array_keys(Artisan::all()); + + $groups = $others = []; + + foreach ($commands as $command) { + $parts = explode(':', $command); + + if (isset($parts[1])) { + $groups[$parts[0]][] = $command; + } else { + $others[] = $command; + } + } + + foreach ($groups as $key => $group) { + if (count($group) === 1) { + $others[] = $group[0]; + + unset($groups[$key]); + } + } + + ksort($groups); + sort($others); + + return compact('groups', 'others'); + } + + protected function renderException(Exception $exception) + { + return sprintf( + "
   %s
", + str_replace("\n", '
', $exception->getMessage()) + ); + } +} + +class StringOutput extends Output +{ + public $output = ''; + + public function clear() + { + $this->output = ''; + } + + protected function doWrite($message, $newline) + { + $this->output .= $message.($newline ? "\n" : ''); + } + + public function getContent() + { + return trim($this->output); + } +} diff --git a/src/Helpers.php b/src/Helpers.php new file mode 100644 index 0000000..c13d7d7 --- /dev/null +++ b/src/Helpers.php @@ -0,0 +1,88 @@ +get('helpers/terminal/database', 'Encore\Admin\Helpers\Controllers\TerminalController@database'); + $router->post('helpers/terminal/database', 'Encore\Admin\Helpers\Controllers\TerminalController@runDatabase'); + $router->get('helpers/terminal/artisan', 'Encore\Admin\Helpers\Controllers\TerminalController@artisan'); + $router->post('helpers/terminal/artisan', 'Encore\Admin\Helpers\Controllers\TerminalController@runArtisan'); + $router->get('helpers/scaffold', 'Encore\Admin\Helpers\Controllers\ScaffoldController@index'); + $router->post('helpers/scaffold', 'Encore\Admin\Helpers\Controllers\ScaffoldController@store'); + $router->get('helpers/routes', 'Encore\Admin\Helpers\Controllers\RouteController@index'); + }); + } + + public static function import() + { + $lastOrder = Menu::max('order'); + + $root = [ + 'parent_id' => 0, + 'order' => $lastOrder++, + 'title' => 'Helpers', + 'icon' => 'fa-gears', + 'uri' => '', + ]; + + $root = Menu::create($root); + + $menus = [ + [ + 'title' => 'Scaffold', + 'icon' => 'fa-keyboard-o', + 'uri' => 'helpers/scaffold', + ], + [ + 'title' => 'Database terminal', + 'icon' => 'fa-database', + 'uri' => 'helpers/terminal/database', + ], + [ + 'title' => 'Laravel artisan', + 'icon' => 'fa-terminal', + 'uri' => 'helpers/terminal/artisan', + ], + [ + 'title' => 'Routes', + 'icon' => 'fa-list-alt', + 'uri' => 'helpers/routes', + ], + ]; + + foreach ($menus as $menu) { + $menu['parent_id'] = $root->id; + $menu['order'] = $lastOrder++; + + Menu::create($menu); + } + + parent::createPermission('Admin helpers', 'ext.helpers', 'helpers/*'); + } +} diff --git a/src/HelpersServiceProvider.php b/src/HelpersServiceProvider.php new file mode 100644 index 0000000..69bd7fa --- /dev/null +++ b/src/HelpersServiceProvider.php @@ -0,0 +1,18 @@ +loadViewsFrom(__DIR__.'/../resources/views', 'laravel-admin-helpers'); + + Helpers::boot(); + } +} diff --git a/src/Scaffold/ControllerCreator.php b/src/Scaffold/ControllerCreator.php new file mode 100644 index 0000000..038f7f7 --- /dev/null +++ b/src/Scaffold/ControllerCreator.php @@ -0,0 +1,128 @@ +name = $name; + + $this->files = $files ?: app('files'); + } + + /** + * Create a controller. + * + * @param string $model + * + * @throws \Exception + * + * @return string + */ + public function create($model) + { + $path = $this->getpath($this->name); + + if ($this->files->exists($path)) { + throw new \Exception("Controller [$this->name] already exists!"); + } + + $stub = $this->files->get($this->getStub()); + + $this->files->put($path, $this->replace($stub, $this->name, $model)); + + return $path; + } + + /** + * @param string $stub + * @param string $name + * @param string $model + * + * @return string + */ + protected function replace($stub, $name, $model) + { + $stub = $this->replaceClass($stub, $name); + + return str_replace( + ['DummyModelNamespace', 'DummyModel'], + [$model, class_basename($model)], + $stub + ); + } + + /** + * Get controller namespace from giving name. + * + * @param string $name + * + * @return string + */ + protected function getNamespace($name) + { + return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); + } + + /** + * Replace the class name for the given stub. + * + * @param string $stub + * @param string $name + * + * @return string + */ + protected function replaceClass($stub, $name) + { + $class = str_replace($this->getNamespace($name).'\\', '', $name); + + return str_replace(['DummyClass', 'DummyNamespace'], [$class, $this->getNamespace($name)], $stub); + } + + /** + * Get file path from giving controller name. + * + * @param $name + * + * @return string + */ + public function getPath($name) + { + $segments = explode('\\', $name); + + array_shift($segments); + + return app_path(implode('/', $segments)).'.php'; + } + + /** + * Get stub file path. + * + * @return string + */ + public function getStub() + { + return __DIR__.'/stubs/controller.stub'; + } +} diff --git a/src/Scaffold/MigrationCreator.php b/src/Scaffold/MigrationCreator.php new file mode 100644 index 0000000..e59935f --- /dev/null +++ b/src/Scaffold/MigrationCreator.php @@ -0,0 +1,121 @@ +ensureMigrationDoesntAlreadyExist($name); + + $path = $this->getPath($name, $path); + + $stub = $this->files->get(__DIR__.'/stubs/create.stub'); + + $this->files->put($path, $this->populateStub($name, $stub, $table)); + + $this->firePostCreateHooks($table); + + return $path; + } + + /** + * Populate stub. + * + * @param string $name + * @param string $stub + * @param string $table + * + * @return mixed + */ + protected function populateStub($name, $stub, $table) + { + return str_replace( + ['DummyClass', 'DummyTable', 'DummyStructure'], + [$this->getClassName($name), $table, $this->bluePrint], + $stub + ); + } + + /** + * Build the table blueprint. + * + * @param array $fields + * @param string $keyName + * @param bool|true $useTimestamps + * @param bool|false $softDeletes + * + * @throws \Exception + * + * @return $this + */ + public function buildBluePrint($fields = [], $keyName = 'id', $useTimestamps = true, $softDeletes = false) + { + $fields = array_filter($fields, function ($field) { + return isset($field['name']) && !empty($field['name']); + }); + + if (empty($fields)) { + throw new \Exception('Table fields can\'t be empty'); + } + + $rows[] = "\$table->increments('$keyName');\n"; + + foreach ($fields as $field) { + + $column = "\$table->{$field['type']}('{$field['name']}')"; + + if ($field['key']) { + $column .= "->{$field['key']}()"; + } + + if ($field['size'] > 0) { + $column .= "->length({$field['size']})"; + } + + if (isset($field['default']) && $field['default']) { + $column .= "->default('{$field['default']}')"; + } + + if (isset($field['comment']) && $field['comment']) { + $column .= "->comment('{$field['comment']}')"; + } + + if (array_get($field, 'nullable') == 'on') { + $column .= '->nullable()'; + } + + $rows[] = $column.";\n"; + } + + if ($useTimestamps) { + $rows[] = "\$table->timestamps();\n"; + } + + if ($softDeletes) { + $rows[] = "\$table->softDeletes();\n"; + } + + $this->bluePrint = trim(implode(str_repeat(' ', 12), $rows), "\n"); + + return $this; + } +} diff --git a/src/Scaffold/ModelCreator.php b/src/Scaffold/ModelCreator.php new file mode 100644 index 0000000..7f4dfc2 --- /dev/null +++ b/src/Scaffold/ModelCreator.php @@ -0,0 +1,238 @@ +tableName = $tableName; + + $this->name = $name; + + $this->files = $files ?: app('files'); + } + + /** + * Create a new migration file. + * + * @param string $keyName + * @param bool|true $timestamps + * @param bool|false $softDeletes + * + * @throws \Exception + * + * @return string + */ + public function create($keyName = 'id', $timestamps = true, $softDeletes = false) + { + $path = $this->getpath($this->name); + + if ($this->files->exists($path)) { + throw new \Exception("Model [$this->name] already exists!"); + } + + $stub = $this->files->get($this->getStub()); + + $stub = $this->replaceClass($stub, $this->name) + ->replaceNamespace($stub, $this->name) + ->replaceSoftDeletes($stub, $softDeletes) + ->replaceTable($stub, $this->name) + ->replaceTimestamp($stub, $timestamps) + ->replacePrimaryKey($stub, $keyName) + ->replaceSpace($stub); + + $this->files->put($path, $stub); + + return $path; + } + + /** + * Get path for migration file. + * + * @param string $name + * + * @return string + */ + public function getPath($name) + { + $segments = explode('\\', $name); + + array_shift($segments); + + return app_path(implode('/', $segments)).'.php'; + } + + /** + * Get namespace of giving class full name. + * + * @param string $name + * + * @return string + */ + protected function getNamespace($name) + { + return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); + } + + /** + * Replace class dummy. + * + * @param string $stub + * @param string $name + * + * @return $this + */ + protected function replaceClass(&$stub, $name) + { + $class = str_replace($this->getNamespace($name).'\\', '', $name); + + $stub = str_replace('DummyClass', $class, $stub); + + return $this; + } + + /** + * Replace namespace dummy. + * + * @param string $stub + * @param string $name + * + * @return $this + */ + protected function replaceNamespace(&$stub, $name) + { + $stub = str_replace( + 'DummyNamespace', $this->getNamespace($name), $stub + ); + + return $this; + } + + /** + * Replace soft-deletes dummy. + * + * @param string $stub + * @param bool $softDeletes + * + * @return $this + */ + protected function replaceSoftDeletes(&$stub, $softDeletes) + { + $import = $use = ''; + + if ($softDeletes) { + $import = "use Illuminate\\Database\\Eloquent\\SoftDeletes;\n"; + $use = "use SoftDeletes;\n"; + } + + $stub = str_replace(['DummyImportSoftDeletesTrait', 'DummyUseSoftDeletesTrait'], [$import, $use], $stub); + + return $this; + } + + /** + * Replace primarykey dummy. + * + * @param string $stub + * @param string $keyName + * + * @return $this + */ + protected function replacePrimaryKey(&$stub, $keyName) + { + $modelKey = $keyName == 'id' ? '' : "protected \$primaryKey = '$keyName';\n"; + + $stub = str_replace('DummyModelKey', $modelKey, $stub); + + return $this; + } + + /** + * Replace Table name dummy. + * + * @param string $stub + * @param string $name + * + * @return $this + */ + protected function replaceTable(&$stub, $name) + { + $class = str_replace($this->getNamespace($name).'\\', '', $name); + + $table = Str::plural(strtolower($class)) !== $this->tableName ? "protected \$table = '$this->tableName';\n" : ''; + + $stub = str_replace('DummyModelTable', $table, $stub); + + return $this; + } + + /** + * Replace timestamps dummy. + * + * @param string $stub + * @param bool $timestamps + * + * @return $this + */ + protected function replaceTimestamp(&$stub, $timestamps) + { + $useTimestamps = $timestamps ? '' : "public \$timestamps = false;\n"; + + $stub = str_replace('DummyTimestamp', $useTimestamps, $stub); + + return $this; + } + + /** + * Replace spaces. + * + * @param string $stub + * + * @return mixed + */ + public function replaceSpace($stub) + { + return str_replace(["\n\n\n", "\n \n"], ["\n\n", ''], $stub); + } + + /** + * Get stub path of model. + * + * @return string + */ + public function getStub() + { + return __DIR__.'/stubs/model.stub'; + } +} diff --git a/src/Scaffold/stubs/controller.stub b/src/Scaffold/stubs/controller.stub new file mode 100644 index 0000000..9415eab --- /dev/null +++ b/src/Scaffold/stubs/controller.stub @@ -0,0 +1,123 @@ +header('Index') + ->description('description') + ->body($this->grid()); + } + + /** + * Show interface. + * + * @param mixed $id + * @param Content $content + * @return Content + */ + public function show($id, Content $content) + { + return $content + ->header('Detail') + ->description('description') + ->body($this->detail($id)); + } + + /** + * Edit interface. + * + * @param mixed $id + * @param Content $content + * @return Content + */ + public function edit($id, Content $content) + { + return $content + ->header('Edit') + ->description('description') + ->body($this->form()->edit($id)); + } + + /** + * Create interface. + * + * @param Content $content + * @return Content + */ + public function create(Content $content) + { + return $content + ->header('Create') + ->description('description') + ->body($this->form()); + } + + /** + * Make a grid builder. + * + * @return Grid + */ + protected function grid() + { + $grid = new Grid(new DummyModel); + + $grid->id('ID'); + $grid->created_at('Created at'); + $grid->updated_at('Updated at'); + + return $grid; + } + + /** + * Make a show builder. + * + * @param mixed $id + * @return Show + */ + protected function detail($id) + { + $show = new Show(DummyModel::findOrFail($id)); + + $show->id('ID'); + $show->created_at('Created at'); + $show->updated_at('Updated at'); + + return $show; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + $form = new Form(new DummyModel); + + $form->display('ID'); + $form->display('Created at'); + $form->display('Updated at'); + + return $form; + } +} diff --git a/src/Scaffold/stubs/create.stub b/src/Scaffold/stubs/create.stub new file mode 100644 index 0000000..ace8eb1 --- /dev/null +++ b/src/Scaffold/stubs/create.stub @@ -0,0 +1,30 @@ +