├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── composer.json ├── phpunit.xml ├── readme.md ├── resources └── stubs │ ├── component.stub │ ├── component.view.stub │ ├── console.stub │ ├── contract.stub │ ├── controller.plain.stub │ ├── controller.stub │ ├── controller_admin.stub │ ├── controller_repository.stub │ ├── event.stub │ ├── example.stub │ ├── exception.stub │ ├── factory.stub │ ├── job.stub │ ├── listener.stub │ ├── livewire.stub │ ├── livewire.view.stub │ ├── many_many_relationship.stub │ ├── middleware.stub │ ├── migration.plain.stub │ ├── migration.stub │ ├── model.plain.stub │ ├── model.stub │ ├── notification.stub │ ├── pivot.stub │ ├── repository.contract.stub │ ├── repository.stub │ ├── request.stub │ ├── schema_change.stub │ ├── schema_create.stub │ ├── seeder.plain.stub │ ├── seeder.stub │ ├── test.stub │ ├── trait.stub │ ├── view.create_edit.b3.stub │ ├── view.create_edit.stub │ ├── view.index.b3.stub │ ├── view.index.stub │ ├── view.show.b3.stub │ ├── view.show.stub │ ├── view.stub │ ├── view.test.stub │ └── view.website.stub ├── src ├── Commands │ ├── ComponentCommand.php │ ├── ConsoleCommand.php │ ├── ContractCommand.php │ ├── ControllerCommand.php │ ├── EventCommand.php │ ├── EventGenerateCommand.php │ ├── ExceptionCommand.php │ ├── FactoryCommand.php │ ├── FileCommand.php │ ├── GeneratorCommand.php │ ├── JobCommand.php │ ├── ListenerCommand.php │ ├── LivewireCommand.php │ ├── MiddlewareCommand.php │ ├── MigrationCommand.php │ ├── MigrationPivotCommand.php │ ├── ModelCommand.php │ ├── NotificationCommand.php │ ├── PublishCommand.php │ ├── RepositoryCommand.php │ ├── RequestCommand.php │ ├── ResourceCommand.php │ ├── SeederCommand.php │ ├── TestCommand.php │ ├── TraitCommand.php │ └── ViewCommand.php ├── Exceptions │ └── GeneratorException.php ├── GeneratorsServiceProvider.php ├── Migrations │ ├── NameParser.php │ ├── SchemaParser.php │ └── SyntaxBuilder.php ├── Traits │ ├── ArgumentsOptions.php │ └── Settings.php └── config │ └── config.php ├── tests ├── ComponentCommandTest.php ├── ConsoleCommandTest.php ├── ContractCommandTest.php ├── ControllerCommandTest.php ├── EventCommandTest.php ├── ExceptionCommandTest.php ├── FactoryCommandTest.php ├── FileCommandTest.php ├── JobCommandTest.php ├── LivewireCommandTest.php ├── MiddlewareCommandTest.php ├── MigrationCommandTest.php ├── ModelCommandTest.php ├── NotificationCommandTest.php ├── RepositoryCommandTest.php ├── RequestCommandTest.php ├── ResourceCommandTest.php ├── SeederCommandTest.php ├── TestCase.php ├── TestCommandTest.php ├── TraitCommandTest.php └── ViewCommandTest.php └── todo.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: bpocallaghan -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | build 4 | vendor 5 | docs 6 | composer.lock 7 | .phpunit.result.cache 8 | tests/temp/database.sqlite 9 | app/ 10 | tests/Unit 11 | tests/Feature 12 | tests/tests/Unit 13 | tests/tests/Feature 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Ben-Piet O'Callaghan 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 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpocallaghan/generators", 3 | "description": "Custom Laravel File Generators with config and publishable stubs.", 4 | "keywords": [ 5 | "laravel", 6 | "generators", 7 | "stubs", 8 | "config", 9 | "commands", 10 | "customization" 11 | ], 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Ben-Piet O'Callaghan", 16 | "email": "bpocallaghan@gmail.com", 17 | "homepage": "http://bpocallaghan.co.za", 18 | "role": "Developer" 19 | } 20 | ], 21 | "require": { 22 | "php": "^8.1", 23 | "symfony/console": "v7.0.4", 24 | "laravel/framework": "^11.0" 25 | }, 26 | "require-dev": { 27 | "orchestra/testbench": "^7.1" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Bpocallaghan\\Generators\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Bpocallaghan\\Generators\\Tests\\": "tests" 37 | } 38 | }, 39 | "extra": { 40 | "laravel": { 41 | "providers": [ 42 | "Bpocallaghan\\Generators\\GeneratorsServiceProvider" 43 | ] 44 | } 45 | }, 46 | "scripts": { 47 | "test": "vendor/bin/phpunit" 48 | }, 49 | "minimum-stability": "dev", 50 | "prefer-stable": true 51 | } 52 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | tests/ 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Laravel File Generators 2 | 3 | Custom Laravel File Generators with a config file and publishable stubs. 4 | You can publish the stubs. You can add your own stubs to generate. 5 | 6 | This package is being used in [Admin Starter Project](https://github.com/bpocallaghan/titan-starter) that focuses on test driven development and has the foundation ready for you. 7 | 8 | ``` 9 | Laravel 5.1 : v2.1.3 10 | Laravel 5.2 - 5.3 : v3.0.3 11 | Laravel 5.4 : v4.1.9 12 | Laravel 5.5 - 5.8 : v5.0.0+ 13 | Laravel 6.0 : v5.1.0+ 14 | Laravel 7.0 : v6.x 15 | Laravel 8.0 : v7.x 16 | Laravel 9.0 : v8.x 17 | Laravel 10.0 : v9.x 18 | ``` 19 | 20 | ## Commands 21 | ```bash 22 | php artisan generate:publish-stubs 23 | php artisan generate:model 24 | php artisan generate:view 25 | php artisan generate:controller 26 | php artisan generate:migration 27 | php artisan generate:migration:pivot 28 | php artisan generate:seed 29 | php artisan generate:resource 30 | php artisan generate:repository 31 | php artisan generate:contract 32 | php artisan generate:notification 33 | php artisan generate:event 34 | php artisan generate:listener 35 | php artisan generate:event-listener 36 | php artisan generate:trait 37 | php artisan generate:job 38 | php artisan generate:console 39 | php artisan generate:middleware 40 | php artisan generate:factory 41 | php artisan generate:test 42 | php artisan generate:file 43 | php artisan generate:exception 44 | php artisan generate:component 45 | php artisan generate:livewire 46 | ``` 47 | 48 | ### Option for all the commands 49 | - `--force` This will override the existing file, if it exists. 50 | - `--test` This will also generate a test file. 51 | 52 | ### Option for all the commands, except `views` and `migration:pivot` 53 | - `--plain` This will use the .plain stub of the command (generate an empty controller) 54 | 55 | ### Customization 56 | This is for all except the `migration` and `migration:pivot` commands 57 | 58 | ``` 59 | php artisan generate:file foo.bar --type=controller 60 | php artisan generate:view foo.bar --stub=view_show --name=baz_show 61 | php artisan generate:file foo.bar --type=controller --stub=controller_custom --name=BazzzController --plain --force 62 | ``` 63 | 64 | You can specify a custom name of the file to be generated. 65 | You can add the --plain or --force options. 66 | You can override the default stub to be used. 67 | You can create your own stubs with the available placeholders. 68 | You can create new settings' types, for example: 69 | - 'exception' => ['namespace' => '\Exceptions', 'path' => './app/Exceptions/', 'postfix' => 'Exception'], 70 | 71 | [Available placeholders](https://github.com/bpocallaghan/generators/blob/master/resources/stubs/example.stub) 72 | 73 | ## Views Custom Stubs 74 | 75 | ``` 76 | php artisan generate:view posts 77 | php artisan generate:view admin.posts --stub=custom 78 | php artisan generate:view admin.posts --stub=another_file 79 | ``` 80 | 81 | ## Installation 82 | 83 | Update your project's `composer.json` file. 84 | 85 | ``` 86 | composer require bpocallaghan/generators --dev 87 | ``` 88 | 89 | Add the Service Provider (Laravel 5.5+ has automatic discovery of packages) 90 | You'll only want to use these generators for local development, add the provider in `app/Providers/AppServiceProvider.php`: 91 | 92 | ```php 93 | public function register() 94 | { 95 | if ($this->app->environment() == 'local') { 96 | $this->app->register(\Bpocallaghan\Generators\GeneratorsServiceProvider::class); 97 | } 98 | } 99 | ``` 100 | 101 | Run `php artisan` command to see the new commands in the `generate:*` section 102 | 103 | ## Usage 104 | 105 | - [Models](#models) 106 | - [Views](#views) 107 | - [Controllers](#controllers) 108 | - [Migrations](#migrations) 109 | - [Pivot Tables](#pivot-tables) 110 | - [Database Seeders](#database-seeders) 111 | - [Resource](#resource) 112 | - [Repository](#repository) 113 | - [Contract](#contract) 114 | - [Notifications](#notifications) 115 | - [Events and Listeners](#events-and-listeners) 116 | - [Trait](#trait) 117 | - [Job](#job) 118 | - [Console](#console) 119 | - [Middleware](#middleware) 120 | - [Factory](#factory) 121 | - [Test](#test) 122 | - [File](#file) 123 | - [Configuration](#configuration) 124 | 125 | ### Models 126 | 127 | ``` 128 | php artisan generate:model bar 129 | php artisan generate:model foo.bar --plain 130 | php artisan generate:model bar --force 131 | php artisan generate:model bar --factory 132 | php artisan generate:model bar --migration 133 | php artisan generate:model bar --migration --schema="title:string, body:text" 134 | ``` 135 | 136 | ### Views 137 | 138 | ``` 139 | php artisan generate:view foo 140 | php artisan generate:view foo.bar 141 | php artisan generate:view foo.bar --stub=view_show 142 | php artisan generate:view foo.bar --name=foo_bar 143 | ``` 144 | 145 | ### Controllers 146 | 147 | ``` 148 | php artisan generate:controller foo 149 | php artisan generate:controller foo.bar 150 | php artisan generate:controller fooBar 151 | php artisan generate:controller bar --plain 152 | php artisan generate:controller BarController --plain 153 | ``` 154 | 155 | - The `Controller` postfix will be added if needed. 156 | 157 | 158 | ### Migrations 159 | 160 | This is very similar as [Jeffrey Way's](https://github.com/laracasts/Laravel-5-Generators-Extended) 161 | 162 | ``` 163 | php artisan generate:migration create_users_table 164 | php artisan generate:migration create_users_table --plain 165 | php artisan generate:migration create_users_table --force 166 | php artisan generate:migration create_posts_table --schema="title:string, body:text, slug:string:unique, published_at:date" 167 | ``` 168 | 169 | ### Pivot Tables 170 | 171 | This is very similar as [Jeffrey Way's](https://github.com/laracasts/Laravel-5-Generators-Extended) 172 | 173 | ``` 174 | php artisan generate:migration:pivot tags posts 175 | ``` 176 | 177 | ### Database Seeders 178 | 179 | ``` 180 | php artisan generate:seed bar 181 | php artisan generate:seed BarTableSeeder 182 | ``` 183 | 184 | - The `TableSeeder` suffix will be added if needed. 185 | 186 | ### Resource 187 | 188 | ``` 189 | php artisan generate:resource bar 190 | php artisan generate:resource foo.bar 191 | php artisan generate:resource foo.bar_baz 192 | php artisan generate:resource bar --schema="title:string, body:text, slug:string:unique, published_at:date" 193 | php artisan generate:resource articles --controller=admin 194 | ``` 195 | 196 | - This will generate a Bar model, BarsController, resources views (in config), create_bars_table migration, BarTableSeeder 197 | - In the config there is a `resource_views` array, you can specify the views that you want to generate there, just make sure the stub exist. 198 | - This will also ask you to generate the 'repository - contract pattern' files. 199 | - The `--controller=admin` allows you to use the controller_admin stub when generating the controller. 200 | 201 | ### Repository 202 | ``` 203 | php artisan generate:repository Posts 204 | ``` 205 | This will generate a Posts Repository file to be used in your controller. 206 | 207 | ### Contract 208 | ``` 209 | php artisan generate:contract Cache 210 | ``` 211 | This will generate a Cache Contract file to be used with your repositories. 212 | 213 | ### Notifications 214 | 215 | ``` 216 | php artisan generate:notification UserRegistered 217 | ``` 218 | 219 | This will generate a UserRegistered notification. 220 | Laravel provides support for sending notifications across a variety of delivery channels, including mail, SMS (via Nexmo), and Slack. Notifications may also be stored in a database so they may be displayed in your web interface. 221 | 222 | ### Events and Listeners 223 | 224 | ``` 225 | php artisan generate:event InvoiceWasPaid 226 | php artisan generate:listener NotifyUserAboutPayment --event=InvoiceWasPaid 227 | php artisan generate:event-listener 228 | ``` 229 | This will generate the event and listener. 230 | Laravel's events provides a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application 231 | 232 | `php artisan generate:event-listener ` 233 | Will generate all the missing events and listeners defined in your EventServiceProvider. 234 | 235 | ### Trait 236 | ``` 237 | php artisan generate:trait Http\Controllers\Traits\Bar 238 | ``` 239 | This will generate a FooBar Trait file. The command will use the name as your namespace. 240 | `generate:trait Foo` will create a file in `app/Foo.php`, `generate:trait Foo\Bar` will create a file in `app/Foo/Bar.php`. 241 | 242 | ### Job 243 | ``` 244 | php artisan generate:job SendReminderEmail 245 | ``` 246 | This will generate a SendReminderEmail Job file. 247 | 248 | ### Console (Artisan Command) 249 | ``` 250 | php artisan generate:console SendEmails 251 | php artisan generate:console SendEmails --command=send:emails 252 | ``` 253 | This will generate a SendEmails Artisan Command file. The --command option is optional. 254 | 255 | ### Middleware 256 | ``` 257 | php artisan generate:middleware AuthenticateAdmin 258 | ``` 259 | This will generate an AuthenticateAdmin Middleware file. 260 | 261 | ### Factory 262 | ``` 263 | php artisan generate:factory Post 264 | php artisan generate:factory PostFactory 265 | ``` 266 | This will generate a PostFactory model file. 267 | 268 | ### Test 269 | ``` 270 | php artisan generate:test UserCanLogin 271 | php artisan generate:test Post --unit 272 | php artisan generate:test Auth\LoginTest 273 | ``` 274 | This will generate Feature\UserCanLogin and Unit\PostTest and Unit\Auth\LoginTest files. 275 | 276 | ### Component 277 | ``` 278 | php artisan generate:component Foo 279 | php artisan generate:component Foo/Bar 280 | php artisan generate:component Baz --test 281 | ``` 282 | This will generate a Laravel Component. The php and blade files will be generated. 283 | You can also specify to generate a unit test. 284 | 285 | ### Livewire 286 | ``` 287 | php artisan generate:livewire Foo 288 | php artisan generate:livewire Foo/Bar 289 | php artisan generate:livewire Baz --test 290 | php artisan generate:livewire foo-bar --request 291 | ``` 292 | This will generate a Livewire component. The php and blade files will be generated. 293 | You can also specify to generate a test or a form request. 294 | 295 | ### Configuration 296 | 297 | ``` 298 | php artisan generate:publish-stubs 299 | ``` 300 | 301 | This will copy the config file to `/config/generators.php`. 302 | Here you can change the defaults for the settings of each `type`, like model, view, controller, seed. 303 | You can also change the namespace, path where to create the file, the pre/post fix, and more. 304 | You can also add new stubs. 305 | 306 | This will also copy all the stubs to `/resources/stubs/`. 307 | Here you can make changes to the current stubs, add your own boilerplate / comments to the files. 308 | You can also add your own stubs here and specify it in the config to be used. 309 | **Migration Stub Note**: The `migration.stub` is only the outer part and the `schema_create.stub or schema_change.stub` is where you modify the schema itself. The `schema_create.stub` has boilerplate added to it. 310 | 311 | ### File 312 | 313 | This is the base command for the view, model, controller, seed commands. 314 | The migration and migration:pivot uses Jeffrey's classes. 315 | In the config there is a `settings` array, this is the 'types' and their settings. You can add more, for example, if you use repositories, you can add it here. 316 | 317 | ``` 318 | php artisan generate:file foo.bar --type=view 319 | php artisan generate:file foo.bar --type=controller 320 | php artisan generate:file foo.bar --type=model 321 | php artisan generate:file foo.bar --type=model --stub=model_custom 322 | ``` 323 | 324 | ## Customizing file was created message to add support for ide opening the files 325 | 326 | Make links for opening output. 327 | Add output_path_handler as a function to your config/generators.php.Example: 328 | 329 | ``` 330 | 'output_path_handler' => static function($path){ 331 | return 'file:///' . base_path() . $path; 332 | }, 333 | ``` 334 | This will output a file schema uri which JetBrain Products (Intellij,Php Storm,Web Storm,...) then can open directly from your terminal. 335 | 336 | ## Thank you 337 | 338 | - Thank you, [Taylor Ottwell](https://github.com/taylorotwell) for [Laravel](http://laravel.com/). 339 | - Thank you, [Jeffrey Way](https://github.com/JeffreyWay) for the awesome resources at [Laracasts](https://laracasts.com/). 340 | 341 | ## My Other Packages 342 | 343 | - [Alert](https://github.com/bpocallaghan/alert) A helper package to flash a bootstrap alert to the browser via a Facade or a helper function. 344 | - [Notify](https://github.com/bpocallaghan/notify) Laravel Flash Notifications with icons and animations and with a timeout 345 | - [Impersonate User](https://github.com/bpocallaghan/impersonate) This allows you to authenticate as any of your customers. 346 | - [Sluggable](https://github.com/bpocallaghan/sluggable) Provides a HasSlug trait that will generate a unique slug when saving your Laravel Eloquent model. 347 | -------------------------------------------------------------------------------- /resources/stubs/component.stub: -------------------------------------------------------------------------------- 1 | 2 | {{-- Any code of your own that you haven’t looked at for six or more months might as well have been written by someone else. --}} 3 | {{-- If you have to spend effort looking at a fragment of code and figuring out what it’s doing, then you should extract it into a function and name the function after the what. --}} 4 | 5 | -------------------------------------------------------------------------------- /resources/stubs/console.stub: -------------------------------------------------------------------------------- 1 | view('index'); 14 | } 15 | } -------------------------------------------------------------------------------- /resources/stubs/controller.stub: -------------------------------------------------------------------------------- 1 | view('{{viewPath}}.index', [ 24 | 'items' => {{model}}::all() 25 | ]); 26 | } 27 | 28 | /** 29 | * Show the form for creating a new {{resource}}. 30 | * 31 | * @return Factory|View 32 | */ 33 | public function create() 34 | { 35 | return $this->view('{{viewPath}}.create_edit'); 36 | } 37 | 38 | /** 39 | * Store a newly created {{resource}} in storage. 40 | * 41 | * @return RedirectResponse|Redirector 42 | */ 43 | public function store({{model}}Request $request) 44 | { 45 | ${{resource}} = $this->createEntry({{model}}::class, $request->validated()); 46 | 47 | return redirect_to_resource(); 48 | } 49 | 50 | /** 51 | * Display the specified {{resource}}. 52 | * 53 | * @param {{model}} ${{resource}} 54 | * @return Factory|View 55 | */ 56 | public function show({{model}} ${{resource}}) 57 | { 58 | return $this->view('{{viewPath}}.show')->with('item', ${{resource}}); 59 | } 60 | 61 | /** 62 | * Show the form for editing the specified {{resource}}. 63 | * 64 | * @param {{model}} ${{resource}} 65 | * @return Factory|View 66 | */ 67 | public function edit({{model}} ${{resource}}) 68 | { 69 | return $this->view('{{viewPath}}.create_edit')->with('item', ${{resource}}); 70 | } 71 | 72 | /** 73 | * Update the specified {{resource}} in storage. 74 | * 75 | * @param {{model}} ${{resource}} 76 | * @return RedirectResponse|Redirector 77 | */ 78 | public function update({{model}}Request $request, {{model}} ${{resource}}) 79 | { 80 | ${{resource}} = $this->updateEntry(${{resource}}, $request->validated()); 81 | 82 | return redirect_to_resource(); 83 | } 84 | 85 | /** 86 | * Remove the specified {{resource}} from storage. 87 | * 88 | * @param {{model}} ${{resource}} 89 | * @return RedirectResponse|Redirector 90 | */ 91 | public function destroy({{model}} ${{resource}}) 92 | { 93 | $this->deleteEntry(${{resource}}, request()); 94 | 95 | return redirect_to_resource(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /resources/stubs/controller_repository.stub: -------------------------------------------------------------------------------- 1 | {{resourceLowercase}} = ${{resourceLowercase}}; 28 | } 29 | 30 | /** 31 | * Display a listing of {{resource}}. 32 | * 33 | * @return Response 34 | */ 35 | public function index() 36 | { 37 | save_resource_url(); 38 | 39 | return $this->view('{{viewPath}}.index')->with('items', {{model}}::all()); 40 | } 41 | 42 | /** 43 | * Show the form for creating a new {{resource}}. 44 | * 45 | * @return Response 46 | */ 47 | public function create() 48 | { 49 | return $this->view('{{viewPath}}.create_edit'); 50 | } 51 | 52 | /** 53 | * Store a newly created {{resource}} in storage. 54 | * 55 | * @param Request $request 56 | * @return Response 57 | */ 58 | public function store(Request $request) 59 | { 60 | $this->validate($request, {{model}}::$rules, {{model}}::$messages); 61 | 62 | $this->createEntry({{model}}::class, $request->all()); 63 | 64 | return redirect_to_resource(); 65 | } 66 | 67 | /** 68 | * Display the specified {{resource}}. 69 | * 70 | * @param {{model}} ${{resource}} 71 | * @return Response 72 | */ 73 | public function show({{model}} ${{resource}}) 74 | { 75 | return $this->view('{{viewPath}}.show')->with('item', ${{resource}}); 76 | } 77 | 78 | /** 79 | * Show the form for editing the specified {{resource}}. 80 | * 81 | * @param {{model}} ${{resource}} 82 | * @return Response 83 | */ 84 | public function edit({{model}} ${{resource}}) 85 | { 86 | return $this->view('{{viewPath}}.create_edit')->with('item', ${{resource}}); 87 | } 88 | 89 | /** 90 | * Update the specified {{resource}} in storage. 91 | * 92 | * @param {{model}} ${{resource}} 93 | * @param Request $request 94 | * @return Response 95 | */ 96 | public function update({{model}} ${{resource}}, Request $request) 97 | { 98 | $this->validate($request, {{model}}::$rules, {{model}}::$messages); 99 | 100 | $this->updateEntry(${{resource}}, $request->all()); 101 | 102 | return redirect_to_resource(); 103 | } 104 | 105 | /** 106 | * Remove the specified {{resource}} from storage. 107 | * 108 | * @param {{model}} ${{resource}} 109 | * @param Request $request 110 | * @return Response 111 | */ 112 | public function destroy({{model}} ${{resource}}, Request $request) 113 | { 114 | $this->deleteEntry(${{resource}}, $request); 115 | 116 | return redirect_to_resource(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /resources/stubs/event.stub: -------------------------------------------------------------------------------- 1 | resource = new {{model}}; 19 | $this->resource->name = ''; 20 | } 21 | 22 | public function rules(): array 23 | { 24 | return (new {{class}}Request())->rules(); 25 | } 26 | 27 | public function submit() 28 | { 29 | $this->validate(); 30 | 31 | $this->resource->save(); 32 | 33 | $this->resetForm(); 34 | 35 | alert()->success("", "Entry saved."); 36 | } 37 | 38 | public function render() 39 | { 40 | return view('livewire.{{view}}'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /resources/stubs/livewire.view.stub: -------------------------------------------------------------------------------- 1 |
2 | {{-- If you don't make mistakes, you're not working on hard enough problems. --}} 3 | {{-- Any fool can write code that a computer can understand. Good programmers write code that humans can understand. --}} 4 |
5 | -------------------------------------------------------------------------------- /resources/stubs/many_many_relationship.stub: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Get the {{model}} many to many 4 | */ 5 | public function {{relationship}}() 6 | { 7 | return $this->belongsToMany({{model}}::class); 8 | } 9 | -------------------------------------------------------------------------------- /resources/stubs/middleware.stub: -------------------------------------------------------------------------------- 1 | line('The introduction to the notification.') 43 | ->action('Notification Action', url('/')) 44 | ->line('Thank you for using our application!'); 45 | } 46 | 47 | /** 48 | * Get the array representation of the notification. 49 | * 50 | * @param mixed $notifiable 51 | * @return array 52 | */ 53 | public function toArray($notifiable) 54 | { 55 | return [ 56 | // 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /resources/stubs/pivot.stub: -------------------------------------------------------------------------------- 1 | integer('{{columnOne}}_id')->unsigned()->index(); 17 | $table->foreign('{{columnOne}}_id')->references('id')->on('{{tableOne}}')->onDelete('cascade'); 18 | $table->integer('{{columnTwo}}_id')->unsigned()->index(); 19 | $table->foreign('{{columnTwo}}_id')->references('id')->on('{{tableTwo}}')->onDelete('cascade'); 20 | $table->primary(['{{columnOne}}_id', '{{columnTwo}}_id']); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::drop('{{pivotTableName}}'); 32 | } 33 | } -------------------------------------------------------------------------------- /resources/stubs/repository.contract.stub: -------------------------------------------------------------------------------- 1 | {{resourceLowercase}} = ${{resourceLowercase}}; 25 | } 26 | 27 | public function all() 28 | { 29 | return $this->{{resourceLowercase}}->all(); 30 | } 31 | 32 | /** 33 | * @param Request $request 34 | * @return mixed 35 | */ 36 | public function getColumn(Request $request) 37 | { 38 | // TODO: Implement getColumn() method. 39 | } 40 | 41 | /** 42 | * @param Request $request 43 | * @return mixed 44 | */ 45 | public function getList(Request $request) 46 | { 47 | // TODO: Implement getList() method. 48 | } 49 | 50 | /** 51 | * @param Request $request 52 | * @return mixed 53 | */ 54 | public function create(Request $request) 55 | { 56 | // TODO: Implement create() method. 57 | } 58 | 59 | /** 60 | * @param Request $request 61 | * @param $id 62 | * @return mixed 63 | */ 64 | public function update(Request $request, $id) 65 | { 66 | // TODO: Implement update() method. 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /resources/stubs/repository.stub: -------------------------------------------------------------------------------- 1 | check(); 17 | } 18 | 19 | /** 20 | * Get the validation rules that apply to the request. 21 | * 22 | * @return array 23 | */ 24 | public function rules() 25 | { 26 | return [ 27 | //'name' => 'required|min:3|max:245', 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /resources/stubs/schema_change.stub: -------------------------------------------------------------------------------- 1 | Schema::table('{{table}}', function(Blueprint $table) { 2 | {{schema_up}} 3 | }); -------------------------------------------------------------------------------- /resources/stubs/schema_create.stub: -------------------------------------------------------------------------------- 1 | Schema::create('{{table}}', function (Blueprint $table) { 2 | $table->bigIncrements('id')->unique()->index(); 3 | {{schema_up}} 4 | $table->timestamps(); 5 | $table->softDeletes(); 6 | $table->integer('created_by')->unsigned(); 7 | $table->integer('updated_by')->unsigned()->nullable(); 8 | $table->integer('deleted_by')->unsigned()->nullable(); 9 | }); -------------------------------------------------------------------------------- /resources/stubs/seeder.plain.stub: -------------------------------------------------------------------------------- 1 | $item) 21 | { 22 | {{model}}::create([ 23 | 24 | ]); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/stubs/test.stub: -------------------------------------------------------------------------------- 1 | 5 |
6 |
7 |
8 |

9 | 10 | {{ isset($item)? 'Edit the ' . $item->name . ' entry': 'Create a new {{model}}' }} 11 |

12 |
13 | 14 |
15 | 16 | @include('titan::admin.partials.info') 17 | 18 |
id}" : '')}}" accept-charset="UTF-8" enctype="multipart/form-data"> 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 | 27 | 28 | {!! form_error_message('name', $errors) !!} 29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 | 37 |
38 | 39 | 40 |
41 | {!! form_error_message('active_from', $errors) !!} 42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 | 50 | 51 |
52 | {!! form_error_message('active_to', $errors) !!} 53 |
54 |
55 |
56 | 57 |
58 |
59 |
60 | 61 |
62 | 63 | 64 | 65 | 66 | 67 |
68 | {!! form_error_message('photo', $errors) !!} 69 |
70 | @if(isset($item) && $item && $item->image) 71 |
72 | 73 | 74 |
75 | @endif 76 |
77 | 78 |
79 |
80 | 86 |
87 | 88 | 89 | 90 | 91 | 92 |
93 | {!! form_error_message('file', $errors) !!} 94 |
95 |
96 |
97 | 98 |
99 | 100 | 101 | {!! form_error_message('content', $errors) !!} 102 |
103 |
104 | 105 | @include('titan::admin.partials.form_footer') 106 |
107 |
108 |
109 |
110 | 111 | @endsection 112 | 113 | @section('scripts') 114 | @parent 115 | 122 | @endsection 123 | -------------------------------------------------------------------------------- /resources/stubs/view.create_edit.stub: -------------------------------------------------------------------------------- 1 | @extends('admin.admin') 2 | 3 | @section('content') 4 |
5 |
6 |

7 | 8 | {{ isset($item)? 'Edit the ' . $item->name . ' entry': 'Create a new {{model}}' }} 9 |

10 | 11 |
12 | 15 |
16 |
17 | 18 |
id}" : '')}}" accept-charset="UTF-8" enctype="multipart/form-data"> 19 | 20 | 21 | 22 |
23 | @include('admin.partials.info') 24 | 25 |
26 |
27 |
28 |
29 | 30 | 31 | {!! form_error_message('name', $errors) !!} 32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 | 40 |
41 | 42 | 43 |
44 | {!! form_error_message('active_from', $errors) !!} 45 |
46 |
47 | 48 |
49 |
50 | 51 |
52 | 53 | 54 |
55 | {!! form_error_message('active_to', $errors) !!} 56 |
57 |
58 |
59 | 60 |
61 |
62 |
63 | 64 |
65 | 66 | 67 | 68 | 69 | 70 |
71 | {!! form_error_message('photo', $errors) !!} 72 |
73 | @if(isset($item) && $item && $item->image) 74 |
75 | 76 | 77 |
78 | @endif 79 |
80 | 81 |
82 |
83 | 89 |
90 | 91 | 92 | 93 | 94 | 95 |
96 | {!! form_error_message('file', $errors) !!} 97 |
98 |
99 |
100 | 101 |
102 | 103 | 104 | {!! form_error_message('content', $errors) !!} 105 |
106 |
107 |
108 | 111 |
112 |
113 | @endsection 114 | 115 | @section('scripts') 116 | @parent 117 | 124 | @endsection 125 | -------------------------------------------------------------------------------- /resources/stubs/view.index.b3.stub: -------------------------------------------------------------------------------- 1 | @extends('titan::layouts.admin') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |

9 | 10 | List All {{collectionUpper}} 11 |

12 |
13 | 14 |
15 | 16 | @include('titan::admin.partials.info') 17 | 18 | @include('titan::admin.partials.toolbar') 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | @foreach ($items as $item) 31 | 32 | 33 | 34 | 35 | 36 | 37 | @endforeach 38 | 39 |
{{model}}DescriptionCreatedAction
{{ $item->name }}{!! $item->content !!}{{ $item->created_at->format('d M Y') }}{!! action_row($selectedNavigation->url, $item->id, $item->name, ['show', 'edit', 'delete']) !!}
40 |
41 |
42 |
43 |
44 | @endsection 45 | -------------------------------------------------------------------------------- /resources/stubs/view.index.stub: -------------------------------------------------------------------------------- 1 | @extends('admin.admin') 2 | 3 | @section('content') 4 |
5 |
6 |

List All {{collectionUpper}}

7 | 8 |
9 | 12 |
13 |
14 | 15 |
16 | @include('admin.partials.info') 17 | 18 | @include('admin.partials.card.buttons') 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | @foreach ($items as $item) 31 | 32 | 33 | 34 | 35 | 36 | 37 | @endforeach 38 | 39 |
{{model}}DescriptionCreatedAction
{{ $item->name }}{!! $item->content !!}{{ $item->created_at->format('d M Y') }}{!! action_row($selectedNavigation->url, $item->id, $item->name, ['show', 'edit', 'delete']) !!}
40 |
41 |
42 | @endsection 43 | -------------------------------------------------------------------------------- /resources/stubs/view.show.b3.stub: -------------------------------------------------------------------------------- 1 | @extends('titan::layouts.admin') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |

9 | 10 | {{collectionUpper}} - {{ $item->name }} 11 |

12 |
13 | 14 |
15 | 16 | @include('titan::admin.partials.info') 17 | 18 |
19 |
20 |
21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 |
36 | 37 |
38 | {!! $item->description !!} 39 |
40 |
41 |
42 |
43 | 44 | @include('titan::admin.partials.form_footer', ['submit' => false]) 45 |
46 |
47 |
48 |
49 |
50 | @endsection 51 | -------------------------------------------------------------------------------- /resources/stubs/view.show.stub: -------------------------------------------------------------------------------- 1 | 2 | @extends('admin.admin') 3 | 4 | @section('content') 5 |
6 |
7 |

{{collectionUpper}} - {{ $item->name }}

8 | 9 |
10 | 13 |
14 |
15 | 16 |
17 | @include('admin.partials.info') 18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 | 37 |
38 | 39 |
40 | {!! $item->description !!} 41 |
42 |
43 |
44 |
45 |
46 | 49 |
50 | @endsection 51 | -------------------------------------------------------------------------------- /resources/stubs/view.stub: -------------------------------------------------------------------------------- 1 | {{path}} -------------------------------------------------------------------------------- /resources/stubs/view.test.stub: -------------------------------------------------------------------------------- 1 | view('{{view}}.index')->with('items', {{model}}::all()); 18 | } 19 | 20 | /** 21 | * Show the form for creating a new {{resource}}. 22 | * 23 | * @return Response 24 | */ 25 | public function create() 26 | { 27 | return $this->view('{{view}}.add_edit'); 28 | } 29 | 30 | public function store(Request $request) 31 | { 32 | $this->validate($request, {{model}}::$rules, {{model}}::$messages); 33 | 34 | ${{resource}} = $this->createEntry('App\Models\{{model}}', $request->all()); 35 | 36 | return Redirect::route('{{view}}.index'); 37 | } 38 | 39 | /** 40 | * Display the specified {{resource}}. 41 | * 42 | * @param {{model}} ${{resource}} 43 | * @return Response 44 | */ 45 | public function show({{model}} ${{resource}}) 46 | { 47 | return $this->view('{{view}}.show')->with('item', ${{resource}}); 48 | } 49 | } -------------------------------------------------------------------------------- /resources/stubs/view.website.stub: -------------------------------------------------------------------------------- 1 | @extends('layouts.website') 2 | 3 | @section('content') 4 |
5 |
6 | @include('website.pages.page_header') 7 | 8 |
9 | 10 |
11 |
12 | 13 |
14 | @include('website.pages.page_side') 15 |
16 |
17 | @endsection 18 | 19 | @section('scripts') 20 | @parent 21 | 26 | @endsection -------------------------------------------------------------------------------- /src/Commands/ComponentCommand.php: -------------------------------------------------------------------------------- 1 | call('generate:file', [ 34 | 'name' => $this->argumentName(), 35 | '--type' => strtolower($this->type) . '_view', 36 | '--stub' => strtolower($this->type) . '_view', 37 | ]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Commands/ConsoleCommand.php: -------------------------------------------------------------------------------- 1 | laravel->getProvider(EventServiceProvider::class); 36 | 37 | foreach ($provider->listens() as $event => $listeners) { 38 | $this->makeEventAndListeners($event, $listeners); 39 | } 40 | 41 | $this->info('Events and listeners generated successfully!'); 42 | } 43 | 44 | /** 45 | * Make the event and listeners for the given event. 46 | * 47 | * @param string $event 48 | * @param array $listeners 49 | * @return void 50 | */ 51 | protected function makeEventAndListeners($event, $listeners) 52 | { 53 | if (! Str::contains($event, '\\')) { 54 | return; 55 | } 56 | 57 | $this->call('generate:event', ['name' => $event]); 58 | 59 | $this->makeListeners($event, $listeners); 60 | } 61 | 62 | /** 63 | * Make the listeners for the given event. 64 | * 65 | * @param string $event 66 | * @param array $listeners 67 | * @return void 68 | */ 69 | protected function makeListeners($event, $listeners) 70 | { 71 | foreach ($listeners as $listener) { 72 | $listener = preg_replace('/@.+$/', '', $listener); 73 | 74 | $this->call('generate:listener', ['name' => $listener, '--event' => $event]); 75 | } 76 | } 77 | 78 | /** 79 | * Get the console command arguments. 80 | * 81 | * @return array 82 | */ 83 | protected function getArguments() 84 | { 85 | return []; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Commands/ExceptionCommand.php: -------------------------------------------------------------------------------- 1 | getArgumentNameOnly(); 36 | 37 | switch ($this->option('type')) { 38 | case 'view': 39 | break; 40 | case 'model': 41 | $name = $this->getModelName(); 42 | break; 43 | case 'controller': 44 | case 'livewire': 45 | case 'component': 46 | $name = $this->getControllerName($name); 47 | break; 48 | case 'livewire_view': 49 | case 'component_view': 50 | $name = $this->getViewName($name); 51 | break; 52 | case 'seeder': 53 | $name = $this->getSeederName($name); 54 | break; 55 | } 56 | 57 | // override the name 58 | if ($this->option('name')) { 59 | return $this->option('name') . $this->settings['file_type']; 60 | } 61 | 62 | return $this->settings['prefix'] . $name . $this->settings['postfix'] . $this->settings['file_type']; 63 | } 64 | 65 | /** 66 | * Execute the console command. 67 | * @return void 68 | * @throws FileNotFoundException 69 | */ 70 | public function handle() 71 | { 72 | $this->setSettings(); 73 | $this->getResourceName($this->getUrl(false)); 74 | 75 | // check the path where to create and save file 76 | $path = $this->getPath(''); 77 | if ($this->files->exists($path) && $this->optionForce() === false) { 78 | return $this->error($this->type . ' already exists!'); 79 | } 80 | 81 | // make all the directories 82 | $this->makeDirectory($path); 83 | 84 | // build file and save it at location 85 | $this->files->put($path, $this->buildClass($this->argumentName())); 86 | 87 | // check if there is an output handler function 88 | $output_handler = config('generators.output_path_handler'); 89 | $this->info(ucfirst($this->option('type')) . ' created successfully.'); 90 | if (is_callable($output_handler)) { 91 | // output to console from the user defined function 92 | $this->info($output_handler(Str::after($path, '.'))); 93 | } else { 94 | // output to console 95 | $this->info('- ' . $path); 96 | } 97 | 98 | // if we need to run "composer dump-autoload" 99 | if ($this->settings['dump_autoload'] === true) { 100 | if ($this->confirm("Run 'composer dump-autoload'?")) { 101 | $this->composer->dumpAutoloads(); 102 | } 103 | } 104 | 105 | // if we need to generate a test file 106 | if ($this->option('test')) { 107 | // ./app/Http 108 | $name = Str::replace('./app', '', $path); 109 | $name = Str::replace('/Http/', '', $name); 110 | $name = Str::replace('.php', '', $name); 111 | 112 | $this->call('generate:test', [ 113 | 'name' => $name, 114 | '--unit' => !(Str::contains($this->settings['namespace'], 'Http\\')), 115 | ]); 116 | } 117 | } 118 | 119 | /** 120 | * Get the destination class path. 121 | * 122 | * @param string $name 123 | * @return string 124 | */ 125 | protected function getPath($name) 126 | { 127 | $name = $this->getFileName(); 128 | 129 | $withName = (bool)$this->option('name'); 130 | 131 | $path = $this->settings['path']; 132 | 133 | if ($this->settingsDirectoryNamespace() === true) { 134 | $path .= $this->getArgumentPath($withName); 135 | } 136 | 137 | $path .= $name; 138 | 139 | return $path; 140 | } 141 | 142 | /** 143 | * Build the class with the given name. 144 | * 145 | * @param string $name 146 | * @return string 147 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 148 | */ 149 | protected function buildClass($name) 150 | { 151 | $stub = $this->files->get($this->getStub()); 152 | 153 | // examples used for the placeholders is for 'foo.bar' 154 | 155 | // App\Foo 156 | $stub = str_replace('{{namespace}}', $this->getNamespace($name), $stub); 157 | 158 | // Foo 159 | $stub = str_replace('{{namespaceWithoutApp}}', $this->getNamespace($name, false), $stub); 160 | 161 | // App\ 162 | $stub = str_replace('{{rootNamespace}}', $this->getLaravel()->getNamespace(), $stub); 163 | 164 | // Bar 165 | $stub = str_replace('{{class}}', $this->getClassName(), $stub); 166 | 167 | $url = $this->getUrl(); // /foo/bar 168 | 169 | // /foo/bar 170 | $stub = str_replace('{{url}}', $this->getUrl(), $stub); 171 | 172 | // bars 173 | $stub = str_replace('{{collection}}', $this->getCollectionName(), $stub); 174 | 175 | // Bars 176 | $stub = str_replace('{{collectionUpper}}', $this->getCollectionUpperName(), $stub); 177 | 178 | // Bar 179 | $stub = str_replace('{{model}}', $this->getModelName(), $stub); 180 | 181 | // Bar 182 | $stub = str_replace('{{resource}}', $this->resource, $stub); 183 | 184 | // bar 185 | $stub = str_replace('{{resourceLowercase}}', $this->resourceLowerCase, $stub); 186 | 187 | // ./resources/views/foo/bar.blade.php 188 | $stub = str_replace('{{path}}', $this->getPath(''), $stub); 189 | 190 | // foos.bars 191 | $stub = str_replace('{{view}}', $this->getViewPath($this->getUrl(false)), $stub); 192 | 193 | // foos.bars (remove admin or website if first word) 194 | $stub = str_replace('{{viewPath}}', $this->getViewPathFormatted($this->getUrl(false)), $stub); 195 | 196 | // bars 197 | $stub = str_replace('{{table}}', $this->getTableName($url), $stub); 198 | 199 | // console command name 200 | $stub = str_replace('{{command}}', $this->option('command'), $stub); 201 | 202 | // contract file name 203 | $stub = str_replace('{{contract}}', $this->getContractName(), $stub); 204 | 205 | // contract namespace 206 | $stub = str_replace('{{contractNamespace}}', $this->getContractNamespace(), $stub); 207 | 208 | return $stub; 209 | } 210 | 211 | /** 212 | * Get the full namespace name for a given class. 213 | * 214 | * @param string $name 215 | * @param bool $withApp 216 | * @return string 217 | */ 218 | protected function getNamespace($name, $withApp = true) 219 | { 220 | $path = (strlen($this->settings['namespace']) >= 2 ? $this->settings['namespace'] . '\\' : ''); 221 | 222 | // dont add the default namespace if specified not to in config 223 | if ($this->settingsDirectoryNamespace() === true) { 224 | $path .= str_replace('/', '\\', $this->getArgumentPath()); 225 | } 226 | 227 | $pieces = array_map('ucfirst', explode('/', $path)); 228 | 229 | $namespace = ($withApp === true ? $this->getLaravel()->getNamespace() : '') . implode('\\', $pieces); 230 | 231 | $namespace = rtrim(ltrim(str_replace('\\\\', '\\', $namespace), '\\'), '\\'); 232 | 233 | return $namespace; 234 | } 235 | 236 | /** 237 | * Get the url for the given name 238 | * 239 | * @param bool $lowercase 240 | * @return string 241 | */ 242 | protected function getUrl($lowercase = true) 243 | { 244 | if ($lowercase) { 245 | $url = '/' . rtrim(implode( 246 | '/', 247 | array_map('Str::snake', explode('/', $this->getArgumentPath(true))) 248 | ), '/'); 249 | $url = (implode('/', array_map('Str::slug', explode('/', $url)))); 250 | 251 | return $url; 252 | } 253 | 254 | return '/' . rtrim(implode('/', explode('/', $this->getArgumentPath(true))), '/'); 255 | } 256 | 257 | /** 258 | * Get the class name 259 | * @return mixed 260 | */ 261 | protected function getClassName() 262 | { 263 | return ucwords(Str::camel(str_replace( 264 | [$this->settings['file_type']], 265 | [''], 266 | $this->getFileName() 267 | ))); 268 | } 269 | 270 | /** 271 | * Get the console command options. 272 | * 273 | * @return array 274 | */ 275 | protected function getOptions() 276 | { 277 | return array_merge([ 278 | ['type', null, InputOption::VALUE_OPTIONAL, 'The type of file: model, view, controller, migration, seed', 'view'], 279 | // optional for to generate:console 280 | ['command', null, InputOption::VALUE_OPTIONAL, 'The terminal command that should be assigned.', 'command:name'], 281 | // optional for to generate:test 282 | ['unit', null, InputOption::VALUE_OPTIONAL, 'Create a unit test.', 'Feature'], 283 | ], parent::getOptions()); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/Commands/GeneratorCommand.php: -------------------------------------------------------------------------------- 1 | composer = $composer; 47 | } 48 | 49 | /** 50 | * Execute the console command. 51 | * 52 | * @return void 53 | */ 54 | public function handle() 55 | { 56 | $args = [ 57 | 'name' => $this->argumentName(), 58 | '--type' => strtolower($this->type), // settings type 59 | '--plain' => $this->optionPlain(), // if plain stub 60 | '--force' => $this->optionForce(), // force override 61 | '--stub' => $this->optionStub(), // custom stub name 62 | '--name' => $this->optionName(), // custom name for file 63 | '--test' => $this->optionTest(), // also generate test file 64 | ]; 65 | 66 | // extra custom option 67 | if ($this->extraOption) { 68 | $args["--{$this->extraOption}"] = $this->optionExtra(); 69 | } 70 | 71 | $this->call('generate:file', $args); 72 | } 73 | 74 | /** 75 | * Only return the name of the file 76 | * Ignore the path / namespace of the file 77 | * 78 | * @return array|mixed|string 79 | */ 80 | protected function getArgumentNameOnly() 81 | { 82 | $name = $this->argumentName(); 83 | 84 | if (Str::contains($name, '/')) { 85 | $name = str_replace('/', '.', $name); 86 | } 87 | 88 | if (Str::contains($name, '\\')) { 89 | $name = str_replace('\\', '.', $name); 90 | } 91 | 92 | if (Str::contains($name, '.')) { 93 | return substr($name, strrpos($name, '.') + 1); 94 | } 95 | 96 | return $name; 97 | } 98 | 99 | /** 100 | * Return the path of the file 101 | * 102 | * @param bool $withName 103 | * @return array|mixed|string 104 | */ 105 | protected function getArgumentPath($withName = false) 106 | { 107 | $name = $this->argumentName(); 108 | 109 | if (Str::contains($name, '.')) { 110 | $name = str_replace('.', '/', $name); 111 | } 112 | 113 | if (Str::contains($name, '\\')) { 114 | $name = str_replace('\\', '/', $name); 115 | } 116 | 117 | // ucfirst char, for correct namespace 118 | $name = implode('/', array_map('ucfirst', explode('/', $name))); 119 | 120 | // if we need to keep lowercase 121 | if ($this->settingsDirectoryFormat() === 'strtolower') { 122 | $name = implode('/', array_map('strtolower', explode('/', $name))); 123 | } 124 | 125 | // if type Test -> see if Feature or Unit 126 | if ($this->option('type') === 'test') { 127 | $folder = $this->option('unit') ? 'Unit' : 'Feature'; // Feature unless null -> Unit 128 | 129 | $name = $folder . DIRECTORY_SEPARATOR . $name; 130 | } 131 | 132 | // if we want the path with name 133 | if ($withName) { 134 | return $name . '/'; 135 | } 136 | 137 | if (Str::contains($name, '/')) { 138 | return substr($name, 0, strripos($name, '/') + 1); 139 | } 140 | 141 | // if test - return the prefix folder 142 | if ($this->option('type') === 'test') { 143 | return ($this->option('unit') ? 'Unit' : 'Feature') . DIRECTORY_SEPARATOR; 144 | } 145 | 146 | return ''; 147 | } 148 | 149 | /** 150 | * Get the resource name 151 | * 152 | * @param $name 153 | * @param bool $format 154 | * @return string 155 | */ 156 | protected function getResourceName($name, $format = true) 157 | { 158 | // we assume its already formatted to resource name 159 | if ($name && $format === false) { 160 | return $name; 161 | } 162 | 163 | $name = isset($name) ? $name : $this->resource; 164 | 165 | $this->resource = lcfirst(Str::singular(class_basename($name))); 166 | $this->resourceLowerCase = strtolower($name); 167 | 168 | return $this->resource; 169 | } 170 | 171 | /** 172 | * Get the name for the model 173 | * 174 | * @param null $name 175 | * @return string 176 | */ 177 | protected function getModelName($name = null) 178 | { 179 | $name = isset($name) ? $name : $this->resource; 180 | 181 | //return ucwords(Str::camel($this->getResourceName($name))); 182 | 183 | return Str::singular(ucwords(Str::camel(class_basename($name)))); 184 | } 185 | 186 | /** 187 | * Get the name for the controller 188 | * 189 | * @param null $name 190 | * @return string 191 | */ 192 | protected function getControllerName($name = null) 193 | { 194 | return ucwords(Str::camel(str_replace($this->settings['postfix'], '', ($name)))); 195 | } 196 | 197 | protected function getViewName(string $name = null): string 198 | { 199 | $name = strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $name)); 200 | return (str_replace($this->settings['postfix'], '', $name)); 201 | } 202 | 203 | /** 204 | * Get the name for the seed 205 | * 206 | * @param null $name 207 | */ 208 | protected function getSeederName($name = null): string 209 | { 210 | return ucwords(Str::camel(str_replace( 211 | $this->settings['postfix'], 212 | '', 213 | $this->getCollectionName($name) 214 | ))); 215 | } 216 | 217 | /** 218 | * Get the name of the collection 219 | * 220 | * @param null $name 221 | * @return string 222 | */ 223 | protected function getCollectionName($name = null) 224 | { 225 | return Str::plural($this->getResourceName($name)); 226 | } 227 | 228 | /** 229 | * Get the plural uppercase name of the resource 230 | * @param null $name 231 | * @return null|string 232 | */ 233 | protected function getCollectionUpperName($name = null) 234 | { 235 | $name = Str::plural($this->getResourceName($name)); 236 | 237 | $pieces = explode('_', $name); 238 | $name = ""; 239 | foreach ($pieces as $k => $str) { 240 | $name .= ucfirst($str); 241 | } 242 | 243 | return $name; 244 | } 245 | 246 | /** 247 | * Get the name of the contract 248 | * @param null $name 249 | * @return string 250 | */ 251 | protected function getContractName($name = null) 252 | { 253 | $name = isset($name) ? $name : $this->resource; 254 | 255 | $name = Str::singular(ucwords(Str::camel(class_basename($name)))); 256 | 257 | return $name . config('generators.settings.contract.postfix'); 258 | } 259 | 260 | /** 261 | * Get the namespace of where contract was created 262 | * @param bool $withApp 263 | * @return string 264 | */ 265 | protected function getContractNamespace($withApp = true) 266 | { 267 | // get path from settings 268 | $path = config('generators.settings.contract.namespace') . '\\'; 269 | 270 | // dont add the default namespace if specified not to in config 271 | $path .= str_replace('/', '\\', $this->getArgumentPath()); 272 | 273 | $pieces = array_map('ucfirst', explode('/', $path)); 274 | 275 | $namespace = ($withApp === true ? $this->getLaravel()->getNamespace() : '') . implode('\\', $pieces); 276 | 277 | $namespace = rtrim(ltrim(str_replace('\\\\', '\\', $namespace), '\\'), '\\'); 278 | 279 | return $namespace; 280 | } 281 | 282 | /** 283 | * Get the path to the view file 284 | * 285 | * @param $name 286 | * @return string 287 | */ 288 | protected function getViewPath($name, $plural = false) 289 | { 290 | $pieces = explode('/', $name); 291 | 292 | // dont plural if reserve word 293 | foreach ($pieces as $k => $value) { 294 | if (!in_array($value, config('generators.reserve_words'))) { 295 | if (!$plural) { 296 | $pieces[$k] = Str::snake($pieces[$k], '-'); 297 | } else { 298 | $pieces[$k] = Str::plural(Str::snake($pieces[$k], '-')); 299 | } 300 | } 301 | } 302 | 303 | $name = implode('.', $pieces); 304 | 305 | return strtolower(rtrim(ltrim($name, '.'), '.')); 306 | } 307 | 308 | /** 309 | * Remove 'admin' and 'webiste' if first in path 310 | * The Base Controller has it as a 'prefix path' 311 | * 312 | * @param $name 313 | * @return string 314 | */ 315 | protected function getViewPathFormatted($name) 316 | { 317 | $path = $this->getViewPath($name); 318 | 319 | if (strpos($path, 'admin.') === 0) { 320 | $path = substr($path, 6); 321 | } 322 | 323 | if (strpos($path, 'admins.') === 0) { 324 | $path = substr($path, 7); 325 | } 326 | 327 | if (strpos($path, 'website.') === 0) { 328 | $path = substr($path, 8); 329 | } 330 | 331 | if (strpos($path, 'websites.') === 0) { 332 | $path = substr($path, 9); 333 | } 334 | 335 | return $path; 336 | } 337 | 338 | /** 339 | * Get the table name 340 | * 341 | * @param $name 342 | * @return string 343 | */ 344 | protected function getTableName($name) 345 | { 346 | return str_replace("-", "_", Str::plural(Str::snake(class_basename($name)))); 347 | } 348 | 349 | /** 350 | * Get name of file/class with the pre and post fix 351 | * 352 | * @param $name 353 | * @return string 354 | */ 355 | protected function getFileNameComplete($name) 356 | { 357 | return $this->settings['prefix'] . $name . $this->settings['postfix']; 358 | } 359 | 360 | /** 361 | * Get the default namespace for the class. 362 | * 363 | * @param string $rootNamespace 364 | * @return string 365 | */ 366 | protected function getDefaultNamespace($rootNamespace) 367 | { 368 | return $rootNamespace . config('generators.' . strtolower($this->type) . '_namespace'); 369 | } 370 | 371 | /** 372 | * Get the stub file for the generator. 373 | * 374 | * @return string 375 | */ 376 | protected function getStub() 377 | { 378 | $key = $this->getOptionStubKey(); 379 | $stub = config('generators.stubs.' . $key); 380 | if ($stub === null) { 381 | if (app()->environment() === 'testing') { 382 | // Tests\TestCase.php 383 | dump('The stub does not exist in the config file - "' . $key . '"'); 384 | } 385 | $this->error('The stub does not exist in the config file - "' . $key . '"'); 386 | exit; 387 | } 388 | 389 | return $stub; 390 | } 391 | 392 | /** 393 | * Get the key where the stub is located 394 | * 395 | * @return string 396 | */ 397 | protected function getOptionStubKey() 398 | { 399 | $plain = $this->option('plain'); 400 | $stub = $this->option('stub') . ($plain ? '_plain' : ''); 401 | 402 | // if no stub, we assume it's the same as the type 403 | if (is_null($this->option('stub'))) { 404 | $stub = $this->option('type') . ($plain ? '_plain' : ''); 405 | } 406 | 407 | return $stub; 408 | } 409 | 410 | /** 411 | * Get the console command arguments. 412 | * 413 | * @return array 414 | */ 415 | protected function getArguments() 416 | { 417 | return [ 418 | ['name', InputArgument::REQUIRED, 'The name of class being generated.'], 419 | ]; 420 | } 421 | 422 | /** 423 | * Get the console command options. 424 | * 425 | * @return array 426 | */ 427 | protected function getOptions() 428 | { 429 | return [ 430 | ['plain', null, InputOption::VALUE_NONE, 'Generate an empty class.'], 431 | ['force', null, InputOption::VALUE_NONE, 'Warning: Override file if it already exist'], 432 | ['stub', null, InputOption::VALUE_OPTIONAL, 'The name of the view stub you would like to generate.'], 433 | ['name', null, InputOption::VALUE_OPTIONAL, 'If you want to override the name of the file that will be generated.'], 434 | ['test', null, InputOption::VALUE_NONE, 'Generate a test file.'], 435 | ]; 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /src/Commands/JobCommand.php: -------------------------------------------------------------------------------- 1 | option('event')) { 39 | return $this->error('Missing required option: --event=*NameOfEvent*'); 40 | } 41 | 42 | // setup 43 | $this->setSettings(); 44 | $this->getResourceName($this->getUrl(false)); 45 | 46 | // check the path where to create and save file 47 | $path = $this->getPath(''); 48 | if ($this->files->exists($path) && $this->optionForce() === false) { 49 | return $this->error($this->type . ' already exists!'); 50 | } 51 | 52 | // make all the directories 53 | $this->makeDirectory($path); 54 | 55 | // build file and save it at location 56 | $this->files->put($path, $this->buildClass($this->argumentName())); 57 | 58 | // output to console 59 | // check if there is an output handler function 60 | $output_handler = config('generators.output_path_handler'); 61 | $this->info(ucfirst($this->option('type')) . ' created successfully.'); 62 | if (is_callable($output_handler)) { 63 | // output to console from the user defined function 64 | $this->info($output_handler(Str::after($path, '.'))); 65 | } else { 66 | // output to console 67 | $this->info('- ' . $path); 68 | } 69 | 70 | // if we need to run "composer dump-autoload" 71 | if ($this->settings['dump_autoload'] === true) { 72 | $this->composer->dumpAutoloads(); 73 | } 74 | } 75 | 76 | /** 77 | * Get the filename of the file to generate 78 | * 79 | * @return string 80 | */ 81 | private function getFileName() 82 | { 83 | $name = $this->getArgumentNameOnly(); 84 | 85 | switch ($this->option('type')) { 86 | case 'view': 87 | 88 | break; 89 | case 'model': 90 | $name = $this->getModelName(); 91 | break; 92 | case 'controller': 93 | $name = $this->getControllerName($name); 94 | break; 95 | case 'seeder': 96 | $name = $this->getSeederName($name); 97 | break; 98 | } 99 | 100 | // override the name 101 | if ($this->option('name')) { 102 | return $this->option('name') . $this->settings['file_type']; 103 | } 104 | 105 | return $this->settings['prefix'] . $name . $this->settings['postfix'] . $this->settings['file_type']; 106 | } 107 | 108 | /** 109 | * Get the destination class path. 110 | * 111 | * @param string $name 112 | * @return string 113 | */ 114 | protected function getPath($name) 115 | { 116 | $name = $this->getFileName(); 117 | 118 | $withName = boolval($this->option('name')); 119 | 120 | $path = $this->settings['path']; 121 | if ($this->settingsDirectoryNamespace() === true) { 122 | $path .= $this->getArgumentPath($withName); 123 | } 124 | 125 | $path .= $name; 126 | 127 | return $path; 128 | } 129 | 130 | /** 131 | * Build the class with the given name. 132 | * 133 | * @param string $name 134 | * @return string 135 | */ 136 | protected function buildClass($name) 137 | { 138 | $stub = $this->files->get($this->getStub()); 139 | 140 | // examples used for the placeholders is for 'foo.bar' 141 | 142 | // App\Foo 143 | $stub = str_replace('{{namespace}}', $this->getNamespace($name), $stub); 144 | 145 | // App\ 146 | $stub = str_replace('{{rootNamespace}}', $this->getLaravel()->getNamespace(), $stub); 147 | 148 | // Bar 149 | $stub = str_replace('{{class}}', $this->getClassName(), $stub); 150 | 151 | $url = $this->getUrl(); // /foo/bar 152 | 153 | // /foo/bar 154 | $stub = str_replace('{{url}}', $this->getUrl(), $stub); 155 | 156 | // bars 157 | $stub = str_replace('{{collection}}', $this->getCollectionName(), $stub); 158 | 159 | // Bars 160 | $stub = str_replace('{{collectionUpper}}', $this->getCollectionUpperName(), $stub); 161 | 162 | // Bar 163 | $stub = str_replace('{{model}}', $this->getModelName(), $stub); 164 | 165 | // Bar 166 | $stub = str_replace('{{resource}}', $this->resource, $stub); 167 | 168 | // bar 169 | $stub = str_replace('{{resourceLowercase}}', $this->resourceLowerCase, $stub); 170 | 171 | // ./resources/views/foo/bar.blade.php 172 | $stub = str_replace('{{path}}', $this->getPath(''), $stub); 173 | 174 | // foos.bars 175 | $stub = str_replace('{{view}}', $this->getViewPath($this->getUrl(false)), $stub); 176 | 177 | // bars 178 | $stub = str_replace('{{table}}', $this->getTableName($url), $stub); 179 | 180 | // event - listeners 181 | $event = $this->option('event'); 182 | 183 | if (!Str::startsWith($event, $this->laravel->getNamespace()) && !Str::startsWith( 184 | $event, 185 | 'Illuminate' 186 | ) 187 | ) { 188 | $event = $this->laravel->getNamespace() . 'Events\\' . $event; 189 | } 190 | 191 | // event class name 192 | $stub = str_replace('{{event}}', class_basename($event), $stub); 193 | 194 | // event with namespace 195 | $stub = str_replace('{{eventAndNamespace}}', $event, $stub); 196 | 197 | return $stub; 198 | } 199 | 200 | /** 201 | * Get the full namespace name for a given class. 202 | * 203 | * @param string $name 204 | * @param bool $withApp 205 | * @return string 206 | */ 207 | protected function getNamespace($name, $withApp = true) 208 | { 209 | $path = (strlen($this->settings['namespace']) >= 2 ? $this->settings['namespace'] . '\\' : ''); 210 | 211 | // dont add the default namespace if specified not to in config 212 | if ($this->settingsDirectoryNamespace() === true) { 213 | $path .= str_replace('/', '\\', $this->getArgumentPath()); 214 | } 215 | 216 | $pieces = array_map('ucfirst', explode('/', $path)); 217 | 218 | $namespace = ($withApp === true ? $this->getLaravel()->getNamespace() : '') . implode('\\', $pieces); 219 | 220 | $namespace = rtrim(ltrim(str_replace('\\\\', '\\', $namespace), '\\'), '\\'); 221 | 222 | return $namespace; 223 | } 224 | 225 | /** 226 | * Get the url for the given name 227 | * 228 | * @param bool $lowercase 229 | * @return string 230 | */ 231 | protected function getUrl($lowercase = true) 232 | { 233 | if ($lowercase) { 234 | $url = '/' . rtrim(implode( 235 | '/', 236 | array_map('Str::snake', explode('/', $this->getArgumentPath(true))) 237 | ), '/'); 238 | $url = (implode('/', array_map('Str::slug', explode('/', $url)))); 239 | 240 | return $url; 241 | } 242 | 243 | return '/' . rtrim(implode('/', explode('/', $this->getArgumentPath(true))), '/'); 244 | } 245 | 246 | /** 247 | * Get the class name 248 | * @return mixed 249 | */ 250 | protected function getClassName() 251 | { 252 | return ucwords(Str::camel(str_replace( 253 | [$this->settings['file_type']], 254 | [''], 255 | $this->getFileName() 256 | ))); 257 | } 258 | 259 | /** 260 | * Get the console command options. 261 | * 262 | * @return array 263 | */ 264 | protected function getOptions() 265 | { 266 | return array_merge([ 267 | ['event', 'e', InputOption::VALUE_REQUIRED, 'The event class being listened for.'], 268 | ['type', null, InputOption::VALUE_OPTIONAL, 'Type is listener', 'listener'] 269 | ], parent::getOptions()); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/Commands/LivewireCommand.php: -------------------------------------------------------------------------------- 1 | call('generate:file', [ 36 | 'name' => $this->argumentName(), 37 | '--type' => strtolower($this->type) . '_view', 38 | '--stub' => strtolower($this->type) . '_view', 39 | ]); 40 | 41 | if ($this->option('request') === true || $this->option('request') === 'true') { 42 | $this->call('generate:request', [ 43 | 'name' => $this->argumentName(), 44 | ]); 45 | } 46 | } 47 | 48 | /** 49 | * Get the console command options. 50 | * @return array 51 | */ 52 | protected function getOptions() 53 | { 54 | return array_merge([ 55 | ['request', null, InputOption::VALUE_NONE, 'Want a request for this component?'], 56 | ], parent::getOptions()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Commands/MiddlewareCommand.php: -------------------------------------------------------------------------------- 1 | meta = (new NameParser)->parse($this->argumentName()); 51 | $name = $this->qualifyClass($this->getNameInput()); 52 | $path = $this->getPath($name); 53 | 54 | if ($this->files->exists($path) && $this->optionForce() === false) { 55 | return $this->error($this->type . ' already exists!'); 56 | } 57 | 58 | $this->makeDirectory($path); 59 | $this->files->put($path, $this->buildClass($name)); 60 | 61 | // check if there is an output handler function 62 | $output_handler = config('generators.output_path_handler'); 63 | $this->info($this->type . ' created successfully.'); 64 | if (is_callable($output_handler)) { 65 | // output to console from the user defined function 66 | $this->info($output_handler(Str::after($path, '.'))); 67 | } else { 68 | // output to console 69 | $this->info('- ' . $path); 70 | } 71 | 72 | // if model is required 73 | if ($this->optionModel() === true || $this->optionModel() === 'true') { 74 | $this->call('generate:model', [ 75 | 'name' => $this->getModelName(), 76 | '--plain' => $this->optionPlain(), 77 | '--force' => $this->optionForce(), 78 | '--schema' => $this->optionSchema() 79 | ]); 80 | } 81 | } 82 | 83 | /** 84 | * Build the class with the given name. 85 | * 86 | * @param string $name 87 | * @return string 88 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 89 | * @throws \Bpocallaghan\Generators\Exceptions\GeneratorException 90 | */ 91 | protected function buildClass($name) 92 | { 93 | $stub = $this->files->get($this->getStub()); 94 | 95 | $this->replaceNamespace($stub, $name); 96 | $this->replaceClassName($stub); 97 | $this->replaceSchema($stub); 98 | $this->replaceTableName($stub); 99 | 100 | return $stub; 101 | } 102 | 103 | /** 104 | * Replace the class name in the stub. 105 | * 106 | * @param string $stub 107 | * @return $this 108 | */ 109 | protected function replaceClassName(&$stub) 110 | { 111 | $className = ucwords(Str::camel($this->argumentName())); 112 | 113 | $stub = str_replace('{{class}}', $className, $stub); 114 | 115 | return $this; 116 | } 117 | 118 | /** 119 | * Replace the schema for the stub. 120 | * 121 | * @param string $stub 122 | * @return $this 123 | * @throws \Bpocallaghan\Generators\Exceptions\GeneratorException 124 | */ 125 | protected function replaceSchema(&$stub) 126 | { 127 | $schema = ''; 128 | if (!$this->optionPlain()) { 129 | if ($schema = $this->optionSchema()) { 130 | $schema = (new SchemaParser)->parse($schema); 131 | } 132 | 133 | $schema = (new SyntaxBuilder)->create($schema, $this->meta); 134 | } 135 | 136 | $stub = str_replace(['{{schema_up}}', '{{schema_down}}'], $schema, $stub); 137 | 138 | return $this; 139 | } 140 | 141 | /** 142 | * Replace the table name in the stub. 143 | * 144 | * @param string $stub 145 | * @return $this 146 | */ 147 | protected function replaceTableName(&$stub) 148 | { 149 | $table = $this->meta['table']; 150 | 151 | $stub = str_replace('{{table}}', $table, $stub); 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Get the class name for the Eloquent model generator. 158 | * 159 | * @param null $name 160 | * @return string 161 | */ 162 | protected function getModelName($name = null) 163 | { 164 | $name = Str::singular($this->meta['table']); 165 | 166 | $model = ''; 167 | $pieces = explode('_', $name); 168 | foreach ($pieces as $k => $str) { 169 | $model = $model . ucwords($str); 170 | } 171 | 172 | return $model; 173 | } 174 | 175 | /** 176 | * Get the path to where we should store the migration. 177 | * 178 | * @param string $name 179 | * @return string 180 | */ 181 | protected function getPath($name) 182 | { 183 | return './database/migrations/' . date('Y_m_d_His') . '_' . $this->argumentName() . '.php'; 184 | } 185 | 186 | /** 187 | * Get the stub file for the generator. 188 | * 189 | * @return string 190 | */ 191 | protected function getStub() 192 | { 193 | return config('generators.stubs.' . strtolower($this->type) . ($this->input->hasOption('plain') && $this->option('plain') ? '_plain' : '')); 194 | } 195 | 196 | /** 197 | * Get the console command options. 198 | * 199 | * @return array 200 | */ 201 | protected function getOptions() 202 | { 203 | return array_merge([ 204 | ['model', 'm', InputOption::VALUE_OPTIONAL, 'Want a model for this table?', true], 205 | ['schema', 's', InputOption::VALUE_OPTIONAL, 'Optional schema to be attached to the migration', null], 206 | ], parent::getOptions()); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/Commands/MigrationPivotCommand.php: -------------------------------------------------------------------------------- 1 | parseName($this->getNameInput()); 39 | $path = $this->getPath($name); 40 | 41 | if ($this->files->exists($path) && $this->optionForce() === false) { 42 | return $this->error($this->type . ' already exists!'); 43 | } 44 | 45 | // if we need to append the parent models 46 | $modelOne = $this->getModelName($this->argument('tableOne')); 47 | $modelTwo = $this->getModelName($this->argument('tableTwo')); 48 | if ($this->confirm("Add Many To Many Relationship in '{$modelOne}' and '{$modelTwo}' Models? [yes|no]")) { 49 | $this->addRelationshipsInParents(); 50 | } 51 | 52 | $this->makeDirectory($path); 53 | $this->files->put($path, $this->buildClass($name)); 54 | 55 | // output to console 56 | // check if there is an output handler function 57 | $output_handler = config('generators.output_path_handler'); 58 | $this->info($this->type . ' created successfully.'); 59 | if (is_callable($output_handler)) { 60 | // output to console from the user defined function 61 | $this->info($output_handler(Str::after($path, '.'))); 62 | } else { 63 | // output to console 64 | $this->info('- ' . $path); 65 | } 66 | } 67 | 68 | /** 69 | * Empty 'name' argument 70 | * 71 | * @return string 72 | */ 73 | protected function getNameInput() 74 | { 75 | return ''; 76 | } 77 | 78 | /** 79 | * Parse the name and format. 80 | * 81 | * @param string $name 82 | * @return string 83 | */ 84 | protected function parseName($name) 85 | { 86 | $tables = array_map('Str::singular', $this->getSortedTableNames()); 87 | $name = implode('', array_map('ucwords', $tables)); 88 | $pieces = explode('_', $name); 89 | $name = implode('', array_map('ucwords', $pieces)); 90 | 91 | return "Create{$name}PivotTable"; 92 | } 93 | 94 | /** 95 | * Get the destination class path. 96 | * 97 | * @param string $name 98 | * @return string 99 | */ 100 | protected function getPath($name = null) 101 | { 102 | return './database/migrations/' . date('Y_m_d_His') . '_create_' . $this->getPivotTableName() . '_pivot_table.php'; 103 | } 104 | 105 | /** 106 | * Build the class with the given name. 107 | * 108 | * @param string $name 109 | * @return string 110 | */ 111 | protected function buildClass($name) 112 | { 113 | $stub = $this->files->get($this->getStub()); 114 | 115 | return $this->replacePivotTableName($stub) 116 | ->replaceSchema($stub) 117 | ->replaceClass($stub, $name); 118 | } 119 | 120 | /** 121 | * Apply the name of the pivot table to the stub. 122 | * 123 | * @param string $stub 124 | * @return $this 125 | */ 126 | protected function replacePivotTableName(&$stub) 127 | { 128 | $stub = str_replace('{{pivotTableName}}', $this->getPivotTableName(), $stub); 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Apply the correct schema to the stub. 135 | * 136 | * @param string $stub 137 | * @return $this 138 | */ 139 | protected function replaceSchema(&$stub) 140 | { 141 | $tables = $this->getSortedTableNames(); 142 | 143 | $stub = str_replace(['{{columnOne}}', '{{columnTwo}}'], 144 | array_merge(array_map('Str::singular', $tables), $tables), $stub); 145 | 146 | $stub = str_replace(['{{tableOne}}', '{{tableTwo}}'], 147 | array_merge(array_map('Str::plural', $tables), $tables), $stub); 148 | 149 | return $this; 150 | } 151 | 152 | /** 153 | * Replace the class name for the given stub. 154 | * 155 | * @param string $stub 156 | * @param string $name 157 | * @return string 158 | */ 159 | protected function replaceClass($stub, $name) 160 | { 161 | $class = str_replace($this->getNamespace($name) . '\\', '', $name); 162 | 163 | return str_replace('{{class}}', $class, $stub); 164 | } 165 | 166 | /** 167 | * Get the name of the pivot table. 168 | * 169 | * @return string 170 | */ 171 | protected function getPivotTableName() 172 | { 173 | return implode('_', array_map('Str::singular', $this->getSortedTableNames())); 174 | } 175 | 176 | /** 177 | * Sort the two tables in alphabetical order. 178 | * 179 | * @return array 180 | */ 181 | protected function getSortedTableNames() 182 | { 183 | $tables = [ 184 | strtolower($this->argument('tableOne')), 185 | strtolower($this->argument('tableTwo')) 186 | ]; 187 | 188 | sort($tables); 189 | 190 | return $tables; 191 | } 192 | 193 | /** 194 | * Append Many to Many Relationships in Parent Models 195 | */ 196 | public function addRelationshipsInParents() 197 | { 198 | $options = config('generators.settings'); 199 | if (!$options['model']) { 200 | $this->info('Model files not found.'); 201 | 202 | return; 203 | } 204 | 205 | $modelSettings = $options['model']; 206 | 207 | // model names 208 | $modelOne = $this->getModelName($this->argument('tableOne')); 209 | $modelTwo = $this->getModelName($this->argument('tableTwo')); 210 | 211 | // model path 212 | $modelOnePath = $modelSettings['path'] . $modelOne . '.php'; 213 | $modelTwoPath = $modelSettings['path'] . $modelTwo . '.php'; 214 | 215 | $this->addRelationshipInModel($modelOnePath, $modelTwo, $this->argument('tableTwo')); 216 | $this->addRelationshipInModel($modelTwoPath, $modelOne, $this->argument('tableOne')); 217 | } 218 | 219 | /** 220 | * Insert the many to many relationship in model 221 | * @param $modelPath 222 | * @param $relationshipModel 223 | * @param $tableName 224 | */ 225 | private function addRelationshipInModel($modelPath, $relationshipModel, $tableName) 226 | { 227 | // load model 228 | $model = $this->files->get($modelPath); 229 | 230 | // get the position where to insert into file 231 | $index = strlen($model) - strpos(strrev($model), '}') - 1; 232 | 233 | // load many to many stub 234 | $stub = $this->files->get(config('generators.stubs.many_many_relationship')); 235 | $stub = str_replace('{{model}}', $relationshipModel, $stub); 236 | $stub = str_replace('{{relationship}}', Str::camel($tableName), $stub); 237 | //$stub = str_replace('{{relationship}}', strtolower(Str::plural($relationshipModel)), $stub); 238 | 239 | // insert many many stub in model 240 | $model = substr_replace($model, $stub, $index, 0); 241 | 242 | // save model file 243 | $this->files->put($modelPath, $model); 244 | 245 | $this->info("{$relationshipModel} many to many Relationship added in {$modelPath}"); 246 | } 247 | 248 | /** 249 | * Get the stub file for the generator. 250 | * 251 | * @return string 252 | */ 253 | protected function getStub() 254 | { 255 | return config('generators.stubs.' . strtolower($this->type)); 256 | } 257 | 258 | /** 259 | * Get the console command arguments. 260 | * 261 | * @return array 262 | */ 263 | protected function getArguments() 264 | { 265 | return [ 266 | ['tableOne', InputArgument::REQUIRED, 'The name of the first table.'], 267 | ['tableTwo', InputArgument::REQUIRED, 'The name of the second table.'] 268 | ]; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/Commands/ModelCommand.php: -------------------------------------------------------------------------------- 1 | option('migration')) { 41 | $this->call('generate:migration', [ 42 | 'name' => $this->getMigrationName(), 43 | '--model' => false, 44 | '--schema' => $this->option('schema') 45 | ]); 46 | } 47 | 48 | if ($this->option('factory')) { 49 | $this->call('generate:factory', [ 50 | 'name' => $this->getArgumentNameOnly(), 51 | ]); 52 | } 53 | } 54 | 55 | /** 56 | * Get the name for the migration 57 | * 58 | * @return string 59 | */ 60 | private function getMigrationName() 61 | { 62 | $name = $this->getArgumentNameOnly(); 63 | $name = preg_replace('/\B([A-Z])/', '_$1', $name); 64 | $name = strtolower($name); 65 | $name = Str::plural($name); 66 | 67 | return "create_{$name}_table"; 68 | } 69 | 70 | /** 71 | * Get the console command options. 72 | * 73 | * @return array 74 | */ 75 | protected function getOptions() 76 | { 77 | return array_merge([ 78 | ['migration', 'm', InputOption::VALUE_NONE, 'Create a new migration file as well.'], 79 | ['factory', 'f', InputOption::VALUE_NONE, 'Create a new factory file as well.'], 80 | ['schema', 's', InputOption::VALUE_OPTIONAL, 'Optional schema to be attached to the migration', null], 81 | ], parent::getOptions()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Commands/NotificationCommand.php: -------------------------------------------------------------------------------- 1 | copyConfigFile(); 31 | $this->copyStubsDirectory(); 32 | $this->updateStubsPathsInConfigFile(); 33 | 34 | $this->info("The config file has been copied to '" . $this->getConfigPath() . "'."); 35 | $this->info("The stubs have been copied to '{$this->option('path')}'."); 36 | } 37 | 38 | /** 39 | * Copy the config file to the default config folder 40 | */ 41 | private function copyConfigFile() 42 | { 43 | $path = $this->getConfigPath(); 44 | 45 | // if generatords config already exist 46 | if ($this->files->exists($path) && $this->option('force') === false) { 47 | $this->error("{$path} already exists! Run 'generate:publish-stubs --force' to override the config file."); 48 | die; 49 | } 50 | 51 | File::copy(__DIR__ . '/../config/config.php', $path); 52 | } 53 | 54 | /** 55 | * Copy the stubs directory 56 | */ 57 | private function copyStubsDirectory() 58 | { 59 | $path = $this->option('path'); 60 | 61 | // if controller stub already exist 62 | if ($this->files->exists($path . DIRECTORY_SEPARATOR . 'controller.stub') && $this->option('force') === false) { 63 | $this->error("Stubs already exists! Run 'generate:publish-stubs --force' to override the stubs."); 64 | die; 65 | } 66 | 67 | File::copyDirectory(__DIR__ . '/../../resources/stubs', $path); 68 | } 69 | 70 | /** 71 | * Update stubs path in the new published config file 72 | */ 73 | private function updateStubsPathsInConfigFile() 74 | { 75 | $updated = str_replace('vendor/bpocallaghan/generators/', '', 76 | File::get($this->getConfigPath())); 77 | File::put($this->getConfigPath(), $updated); 78 | } 79 | 80 | /** 81 | * Get the config file path 82 | * 83 | * @return string 84 | */ 85 | private function getConfigPath() 86 | { 87 | return config_path('generators.php'); 88 | } 89 | 90 | /** 91 | * Get the console command arguments. 92 | * 93 | * @return array 94 | */ 95 | protected function getArguments() 96 | { 97 | return []; 98 | } 99 | 100 | /** 101 | * Get the console command options. 102 | * 103 | * @return array 104 | */ 105 | protected function getOptions() 106 | { 107 | return [ 108 | [ 109 | 'path', 110 | null, 111 | InputOption::VALUE_OPTIONAL, 112 | 'Which directory should the templates be copied to?', 113 | 'resources/stubs' 114 | ], 115 | ['force', null, InputOption::VALUE_NONE, 'Warning: Override files if it already exist'] 116 | ]; 117 | } 118 | 119 | /** 120 | * Get the stub file for the generator. 121 | * 122 | * @return string 123 | */ 124 | protected function getStub() 125 | { 126 | // 127 | } 128 | } -------------------------------------------------------------------------------- /src/Commands/RepositoryCommand.php: -------------------------------------------------------------------------------- 1 | option('contract')) { 38 | parent::handle(); 39 | } else { 40 | $this->call('generate:repository', [ 41 | 'name' => $this->argumentName(), 42 | '--stub' => 'repository_contract', 43 | ]); 44 | } 45 | } 46 | 47 | /** 48 | * Get the console command options. 49 | * 50 | * @return array 51 | */ 52 | protected function getOptions() 53 | { 54 | return array_merge([ 55 | ['contract', 'c', InputOption::VALUE_NONE, 'Use the implements Contract Stub.'], 56 | ], parent::getOptions()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Commands/RequestCommand.php: -------------------------------------------------------------------------------- 1 | resource = $this->getResourceOnly(); 42 | $this->settings = config('generators.defaults'); 43 | 44 | $this->callModel(); 45 | $this->callView(); 46 | $this->callRepository(); 47 | $this->callController(); 48 | $this->callMigration(); 49 | $this->callSeeder(); 50 | $this->callTest(); 51 | $this->callFactory(); 52 | $this->callMigrate(); 53 | 54 | // confirm dump autoload 55 | if ($this->confirm("Run 'composer dump-autoload'?")) { 56 | $this->composer->dumpAutoloads(); 57 | } 58 | 59 | $this->info('All Done!'); 60 | $this->info('Remember to add ' . "`Route::resource('" . str_replace( 61 | '_', 62 | '-', 63 | $this->getCollectionName() 64 | ) . "', '" . $this->getResourceControllerName() . "');`" . ' in `routes\\web.php`'); 65 | } 66 | 67 | /** 68 | * Call the generate:model command 69 | */ 70 | private function callModel(): void 71 | { 72 | $name = $this->getModelName(); 73 | 74 | $resourceString = $this->getResourceOnly(); 75 | $resourceStringLength = strlen($this->getResourceOnly()); 76 | 77 | if ($resourceStringLength > 18) { 78 | $ans = $this->confirm("Your resource {$resourceString} may have too many characters to use for many to many relationships. The length is {$resourceStringLength}. Continue?"); 79 | if ($ans === false) { 80 | echo "generate:resource cancelled!"; 81 | die; 82 | } 83 | } 84 | 85 | if ($this->confirm("Create a $name model?")) { 86 | $this->callCommandFile('model'); 87 | } 88 | } 89 | 90 | /** 91 | * Generate the resource views 92 | */ 93 | private function callView(): void 94 | { 95 | if ($this->confirm("Create crud views for the $this->resource resource?")) { 96 | $views = config('generators.resource_views'); 97 | foreach ($views as $key => $name) { 98 | $resource = $this->argument('resource'); 99 | if (Str::contains($resource, '.')) { 100 | $resource = str_replace('.', '/', $resource); 101 | } 102 | 103 | $this->callCommandFile( 104 | 'view', 105 | $this->getViewPath($resource), 106 | $key . $this->option('view'), 107 | ['--name' => $name] 108 | ); 109 | } 110 | } 111 | } 112 | 113 | /** 114 | * Generate the Repository / Contract Pattern files 115 | */ 116 | private function callRepository(): void 117 | { 118 | // check the config 119 | if (config('generators.settings.controller.repository_contract')) { 120 | if ($this->confirm("Create a repository and contract for the $this->resource resource?")) { 121 | $name = $this->getModelName(); 122 | 123 | $this->repositoryContract = true; 124 | 125 | $this->callCommandFile('contract', $name); 126 | $this->callCommandFile('repository', $name); 127 | 128 | //$contract = $name . config('generators.settings.contract.postfix'); 129 | //$this->callCommandFile('repository', $name, ['--contract' => $contract]); 130 | } 131 | } 132 | } 133 | 134 | /** 135 | * Generate the resource controller 136 | */ 137 | private function callController(): void 138 | { 139 | $name = $this->getResourceControllerName(); 140 | 141 | if ($this->confirm("Create a controller ($name) for the $this->resource resource?")) { 142 | $arg = $this->getArgumentResource(); 143 | $name = substr_replace( 144 | $arg, 145 | Str::plural($this->resource), 146 | strrpos($arg, $this->resource), 147 | strlen($this->resource) 148 | ); 149 | 150 | if ($this->repositoryContract) { 151 | $this->callCommandFile('controller', $name, 'controller_repository'); 152 | } else { 153 | 154 | // if admin - update stub 155 | if (Str::contains($name, 'admin.') || $this->option('controller') === 'admin') { 156 | $this->callCommandFile('controller', $name, 'controller_admin'); 157 | } else { 158 | $this->callCommandFile('controller', $name, 'controller'); 159 | } 160 | } 161 | } 162 | } 163 | 164 | /** 165 | * Call the generate:migration command 166 | */ 167 | private function callMigration(): void 168 | { 169 | $name = $this->getMigrationName($this->option('migration')); 170 | 171 | if ($this->confirm("Create a migration ($name) for the $this->resource resource?")) { 172 | $this->callCommand('migration', $name, [ 173 | '--model' => false, 174 | '--schema' => $this->option('schema') 175 | ]); 176 | } 177 | } 178 | 179 | /** 180 | * Call the generate:seed command 181 | */ 182 | private function callSeeder(): void 183 | { 184 | $name = $this->getSeederName() . config('generators.settings.seeder.postfix'); 185 | 186 | if ($this->confirm("Create a seeder ($name) for the $this->resource resource?")) { 187 | $this->callCommandFile('seeder'); 188 | } 189 | } 190 | 191 | /** 192 | * Call the generate:test command 193 | */ 194 | private function callTest(): void 195 | { 196 | $name = $this->getModelName() . 'Test'; 197 | 198 | if ($this->confirm("Create a test ($name) for the $this->resource resource?")) { 199 | // feature test 200 | $this->callCommandFile('test', Str::plural($name)); 201 | 202 | // unit test 203 | $this->call('generate:file', [ 204 | 'name' => $name, 205 | '--type' => 'test', 206 | '--unit' => 'Unit', 207 | ]); 208 | } 209 | } 210 | 211 | /** 212 | * Call the generate:factory command 213 | */ 214 | private function callFactory(): void 215 | { 216 | $name = $this->getModelName() . 'Factory'; 217 | 218 | if ($this->confirm("Create a factory ($name) for the $this->resource resource?")) { 219 | $this->callCommandFile('factory', $name); 220 | } 221 | } 222 | 223 | /** 224 | * Call the migrate command 225 | */ 226 | protected function callMigrate(): void 227 | { 228 | if ($this->confirm('Migrate the database?')) { 229 | $this->call('migrate'); 230 | } 231 | } 232 | 233 | /** 234 | * @param $command 235 | * @param $name 236 | * @param array $options 237 | */ 238 | private function callCommand($command, $name, $options = []): void 239 | { 240 | $options = array_merge($options, [ 241 | 'name' => $name, 242 | '--plain' => $this->option('plain'), 243 | '--force' => $this->option('force') 244 | ]); 245 | 246 | $this->call('generate:' . $command, $options); 247 | } 248 | 249 | /** 250 | * Call the generate:file command to generate the given file 251 | * 252 | * @param $type 253 | * @param null $name 254 | * @param null $stub 255 | * @param array $options 256 | */ 257 | private function callCommandFile($type, $name = null, $stub = null, $options = []): void 258 | { 259 | $this->call('generate:file', array_merge($options, [ 260 | 'name' => ($name ? $name : $this->argument('resource')), 261 | '--type' => $type, 262 | '--force' => $this->optionForce(), 263 | '--plain' => $this->optionPlain(), 264 | '--stub' => ($stub ?: $this->optionStub()), 265 | ])); 266 | } 267 | 268 | /** 269 | * The resource argument 270 | * Lowercase and singular each word 271 | * 272 | * @return array|mixed|string 273 | */ 274 | private function getArgumentResource() 275 | { 276 | $name = $this->argument('resource'); 277 | if (Str::contains($name, '/')) { 278 | $name = str_replace('/', '.', $name); 279 | } 280 | 281 | if (Str::contains($name, '\\')) { 282 | $name = str_replace('\\', '.', $name); 283 | } 284 | 285 | // lowecase and singular 286 | $name = strtolower(Str::singular($name)); 287 | 288 | return $name; 289 | } 290 | 291 | /** 292 | * If there are '.' in the name, get the last occurence 293 | * 294 | * @return string 295 | */ 296 | private function getResourceOnly() 297 | { 298 | $name = $this->getArgumentResource(); 299 | if (!Str::contains($name, '.')) { 300 | return $name; 301 | } 302 | 303 | return substr($name, strripos($name, '.') + 1); 304 | } 305 | 306 | /** 307 | * Get the Controller name for the resource 308 | * 309 | * @return string 310 | */ 311 | private function getResourceControllerName(): string 312 | { 313 | return $this->getControllerName( 314 | Str::plural($this->resource), 315 | false 316 | ) . config('generators.settings.controller.postfix'); 317 | } 318 | 319 | /** 320 | * Get the name for the migration 321 | * 322 | * @param null $name 323 | * @return string 324 | */ 325 | private function getMigrationName($name = null): string 326 | { 327 | return 'create_' . Str::plural($this->getResourceName($name)) . '_table'; 328 | } 329 | 330 | /** 331 | * Get the console command arguments. 332 | * 333 | * @return array 334 | */ 335 | protected function getArguments() 336 | { 337 | return [ 338 | ['resource', InputArgument::REQUIRED, 'The name of the resource being generated.'], 339 | ]; 340 | } 341 | 342 | /** 343 | * Get the console command options. 344 | * 345 | * @return array 346 | */ 347 | protected function getOptions() 348 | { 349 | return array_merge(parent::getOptions(), [ 350 | [ 351 | 'view', 352 | null, 353 | InputOption::VALUE_OPTIONAL, 354 | 'Specify the stub for the views', 355 | null 356 | ], 357 | [ 358 | 'controller', 359 | null, 360 | InputOption::VALUE_OPTIONAL, 361 | 'Specify the stub for the controller', 362 | null 363 | ], 364 | ['migration', null, InputOption::VALUE_OPTIONAL, 'Optional migration name', null], 365 | [ 366 | 'schema', 367 | 's', 368 | InputOption::VALUE_OPTIONAL, 369 | 'Optional schema to be attached to the migration', 370 | null 371 | ], 372 | ]); 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/Commands/SeederCommand.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom($configPath, 'generators'); 56 | 57 | // register all the artisan commands 58 | $this->registerCommand(PublishCommand::class, 'publish'); 59 | 60 | $this->registerCommand(ModelCommand::class, 'model'); 61 | $this->registerCommand(ViewCommand::class, 'view'); 62 | $this->registerCommand(ControllerCommand::class, 'controller'); 63 | 64 | $this->registerCommand(RequestCommand::class, 'request'); 65 | $this->registerCommand(MiddlewareCommand::class, 'middleware'); 66 | 67 | $this->registerCommand(SeederCommand::class, 'seeder'); 68 | $this->registerCommand(MigrationCommand::class, 'migration'); 69 | $this->registerCommand(MigrationPivotCommand::class, 'migrate.pivot'); 70 | 71 | $this->registerCommand(NotificationCommand::class, 'notification'); 72 | 73 | $this->registerCommand(EventCommand::class, 'event'); 74 | $this->registerCommand(ListenerCommand::class, 'listener'); 75 | $this->registerCommand(EventGenerateCommand::class, 'event.generate'); 76 | 77 | $this->registerCommand(TraitCommand::class, 'trait'); 78 | $this->registerCommand(ContractCommand::class, 'contract'); 79 | $this->registerCommand(RepositoryCommand::class, 'repository'); 80 | 81 | $this->registerCommand(LivewireCommand::class, 'livewire'); 82 | $this->registerCommand(ComponentCommand::class, 'component'); 83 | 84 | $this->registerCommand(TestCommand::class, 'test'); 85 | $this->registerCommand(FactoryCommand::class, 'factory'); 86 | 87 | $this->registerCommand(JobCommand::class, 'job'); 88 | $this->registerCommand(ConsoleCommand::class, 'console'); 89 | 90 | $this->registerCommand(ExceptionCommand::class, 'exception'); 91 | 92 | $this->registerCommand(ResourceCommand::class, 'resource'); 93 | 94 | $this->registerCommand(FileCommand::class, 'file'); 95 | } 96 | 97 | /** 98 | * Register a singleton command 99 | * 100 | * @param $class 101 | * @param $command 102 | */ 103 | private function registerCommand($class, $command) 104 | { 105 | $this->app->singleton($this->commandPath . $command, function ($app) use ($class) { 106 | return $app[$class]; 107 | }); 108 | 109 | $this->commands($this->commandPath . $command); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Migrations/NameParser.php: -------------------------------------------------------------------------------- 1 | $this->getAction($segments), 24 | 'table' => $this->getTableName($segments) 25 | ]; 26 | } 27 | 28 | /** 29 | * Calculate the table name. 30 | * 31 | * @param array $segments 32 | * 33 | * @return array 34 | */ 35 | private function getTableName($segments) 36 | { 37 | $tableName = []; 38 | 39 | foreach ($segments as $segment) { 40 | if ($this->isConnectingWord($segment)) { 41 | break; 42 | } 43 | 44 | $tableName[] = $segment; 45 | } 46 | 47 | return implode('_', array_reverse($tableName)); 48 | } 49 | 50 | /** 51 | * Determine the user's desired action for the migration. 52 | * 53 | * @param array $segments 54 | * 55 | * @return mixed 56 | */ 57 | private function getAction(&$segments) 58 | { 59 | return $this->normalizeActionName(array_pop($segments)); 60 | } 61 | 62 | /** 63 | * Normalize the user's chosen action to name to 64 | * something that we recognize. 65 | * 66 | * @param string $action 67 | * 68 | * @return string 69 | */ 70 | private function normalizeActionName($action) 71 | { 72 | switch ($action) { 73 | case 'create': 74 | case 'make': 75 | return 'create'; 76 | case 'delete': 77 | case 'destroy': 78 | case 'drop': 79 | return 'remove'; 80 | case 'add': 81 | case 'append': 82 | case 'update': 83 | case 'insert': 84 | return 'add'; 85 | default: 86 | return $action; 87 | } 88 | } 89 | 90 | /** 91 | * Determine if the current segment is a connecting word. 92 | * 93 | * @param string $segment 94 | * 95 | * @return bool 96 | */ 97 | private function isConnectingWord($segment) 98 | { 99 | $connectors = ['to', 'from', 'and', 'with', 'for', 'in', 'of', 'on']; 100 | 101 | return in_array($segment, $connectors); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Migrations/SchemaParser.php: -------------------------------------------------------------------------------- 1 | splitIntoFields($schema); 27 | 28 | foreach ($fields as $field) { 29 | $segments = $this->parseSegments($field); 30 | 31 | if ($this->fieldNeedsForeignConstraint($segments)) { 32 | unset($segments['options']['foreign']); 33 | 34 | // If the user wants a foreign constraint, then 35 | // we'll first add the regular field. 36 | $this->addField($segments); 37 | 38 | // And then add another field for the constraint. 39 | $this->addForeignConstraint($segments); 40 | 41 | continue; 42 | } 43 | 44 | $this->addField($segments); 45 | } 46 | 47 | return $this->schema; 48 | } 49 | 50 | /** 51 | * Add a field to the schema array. 52 | * 53 | * @param array $field 54 | * 55 | * @return $this 56 | */ 57 | private function addField($field) 58 | { 59 | $this->schema[] = $field; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Get an array of fields from the given schema. 66 | * 67 | * @param string $schema 68 | * 69 | * @return array 70 | */ 71 | private function splitIntoFields($schema) 72 | { 73 | return preg_split('/,\s?(?![^()]*\))/', $schema); 74 | } 75 | 76 | /** 77 | * Get the segments of the schema field. 78 | * 79 | * @param string $field 80 | * 81 | * @return array 82 | */ 83 | private function parseSegments($field) 84 | { 85 | $segments = explode(':', $field); 86 | 87 | $name = array_shift($segments); 88 | $type = array_shift($segments); 89 | $arguments = []; 90 | $options = $this->parseOptions($segments); 91 | 92 | // Do we have arguments being used here? 93 | // Like: string(100) 94 | if (preg_match('/(.+?)\(([^)]+)\)/', $type, $matches)) { 95 | $type = $matches[1]; 96 | $arguments = explode(',', $matches[2]); 97 | } 98 | 99 | return compact('name', 'type', 'arguments', 'options'); 100 | } 101 | 102 | /** 103 | * Parse any given options into something usable. 104 | * 105 | * @param array $options 106 | * 107 | * @return array 108 | */ 109 | private function parseOptions($options) 110 | { 111 | if (empty($options)) { 112 | return []; 113 | } 114 | 115 | foreach ($options as $option) { 116 | if (Str::contains($option, '(')) { 117 | preg_match('/([a-z]+)\(([^\)]+)\)/i', $option, $matches); 118 | 119 | $results[$matches[1]] = $matches[2]; 120 | } 121 | else { 122 | $results[$option] = true; 123 | } 124 | } 125 | 126 | return $results; 127 | } 128 | 129 | /** 130 | * Add a foreign constraint field to the schema. 131 | * 132 | * @param array $segments 133 | */ 134 | private function addForeignConstraint($segments) 135 | { 136 | $string = sprintf("%s:foreign:references('id'):on('%s')", $segments['name'], $this->getTableNameFromForeignKey($segments['name'])); 137 | 138 | $this->addField($this->parseSegments($string)); 139 | } 140 | 141 | /** 142 | * Try to figure out the name of a table from a foreign key. 143 | * Ex: user_id => users 144 | * 145 | * @param string $key 146 | * 147 | * @return string 148 | */ 149 | private function getTableNameFromForeignKey($key) 150 | { 151 | return Str::plural(str_replace('_id', '', $key)); 152 | } 153 | 154 | /** 155 | * Determine if the user wants a foreign constraint for the field. 156 | * 157 | * @param array $segments 158 | * 159 | * @return bool 160 | */ 161 | private function fieldNeedsForeignConstraint($segments) 162 | { 163 | return array_key_exists('foreign', $segments['options']); 164 | } 165 | } 166 | 167 | -------------------------------------------------------------------------------- /src/Migrations/SyntaxBuilder.php: -------------------------------------------------------------------------------- 1 | createSchemaForUpMethod($schema, $meta); 28 | $down = $this->createSchemaForDownMethod($schema, $meta); 29 | 30 | return compact('up', 'down'); 31 | } 32 | 33 | /** 34 | * Create the schema for the "up" method. 35 | * 36 | * @param string $schema 37 | * @param array $meta 38 | * 39 | * @return string 40 | * @throws GeneratorException 41 | */ 42 | private function createSchemaForUpMethod($schema, $meta) 43 | { 44 | $fields = $this->constructSchema($schema); 45 | 46 | if ($meta['action'] == 'create') { 47 | return $this->insert($fields)->into($this->getCreateSchemaWrapper()); 48 | } 49 | 50 | if ($meta['action'] == 'add') { 51 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 52 | } 53 | 54 | if ($meta['action'] == 'remove') { 55 | $fields = $this->constructSchema($schema, 'Drop'); 56 | 57 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 58 | } 59 | 60 | // Otherwise, we have no idea how to proceed. 61 | throw new GeneratorException; 62 | } 63 | 64 | /** 65 | * Construct the syntax for a down field. 66 | * 67 | * @param array $schema 68 | * @param array $meta 69 | * 70 | * @return string 71 | * @throws GeneratorException 72 | */ 73 | private function createSchemaForDownMethod($schema, $meta) 74 | { 75 | // If the user created a table, then for the down 76 | // method, we should drop it. 77 | if ($meta['action'] == 'create') { 78 | return sprintf("Schema::dropIfExists('%s');", $meta['table']); 79 | } 80 | 81 | // If the user added columns to a table, then for 82 | // the down method, we should remove them. 83 | if ($meta['action'] == 'add') { 84 | $fields = $this->constructSchema($schema, 'Drop'); 85 | 86 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 87 | } 88 | 89 | // If the user removed columns from a table, then for 90 | // the down method, we should add them back on. 91 | if ($meta['action'] == 'remove') { 92 | $fields = $this->constructSchema($schema); 93 | 94 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 95 | } 96 | 97 | // Otherwise, we have no idea how to proceed. 98 | throw new GeneratorException; 99 | } 100 | 101 | /** 102 | * Store the given template, to be inserted somewhere. 103 | * 104 | * @param string $template 105 | * 106 | * @return $this 107 | */ 108 | private function insert($template) 109 | { 110 | $this->template = $template; 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Get the stored template, and insert into the given wrapper. 117 | * 118 | * @param string $wrapper 119 | * @param string $placeholder 120 | * 121 | * @return mixed 122 | */ 123 | private function into($wrapper, $placeholder = 'schema_up') 124 | { 125 | return str_replace('{{' . $placeholder . '}}', $this->template, $wrapper); 126 | } 127 | 128 | /** 129 | * Get the wrapper template for a "create" action. 130 | * 131 | * @return string 132 | */ 133 | private function getCreateSchemaWrapper() 134 | { 135 | return file_get_contents(config('generators.stubs.schema_create')); 136 | } 137 | 138 | /** 139 | * Get the wrapper template for an "add" action. 140 | * 141 | * @return string 142 | */ 143 | private function getChangeSchemaWrapper() 144 | { 145 | return file_get_contents(config('generators.stubs.schema_change')); 146 | } 147 | 148 | /** 149 | * Construct the schema fields. 150 | * 151 | * @param array $schema 152 | * @param string $direction 153 | * 154 | * @return array 155 | */ 156 | private function constructSchema($schema, $direction = 'Add') 157 | { 158 | if (!$schema) { 159 | return ''; 160 | } 161 | 162 | $fields = array_map(function ($field) use ($direction) { 163 | $method = "{$direction}Column"; 164 | 165 | return $this->$method($field); 166 | }, $schema); 167 | 168 | return implode("\n" . str_repeat(' ', 12), $fields); 169 | } 170 | 171 | /** 172 | * Construct the syntax to add a column. 173 | * 174 | * @param string $field 175 | * 176 | * @return string 177 | */ 178 | private function addColumn($field) 179 | { 180 | $syntax = sprintf("\$table->%s('%s')", $field['type'], $field['name']); 181 | 182 | // If there are arguments for the schema type, like decimal('amount', 5, 2) 183 | // then we have to remember to work those in. 184 | if ($field['arguments']) { 185 | $syntax = substr($syntax, 0, -1) . ', '; 186 | 187 | $syntax .= implode(', ', $field['arguments']) . ')'; 188 | } 189 | 190 | foreach ($field['options'] as $method => $value) { 191 | $syntax .= sprintf("->%s(%s)", $method, $value === true ? '' : $value); 192 | } 193 | 194 | return $syntax .= ';'; 195 | } 196 | 197 | /** 198 | * Construct the syntax to drop a column. 199 | * 200 | * @param string $field 201 | * 202 | * @return string 203 | */ 204 | private function dropColumn($field) 205 | { 206 | return sprintf("\$table->dropColumn('%s');", $field['name']); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/Traits/ArgumentsOptions.php: -------------------------------------------------------------------------------- 1 | settings) { 14 | return str_replace($this->settings['postfix'], '', $this->argument('name')); 15 | } 16 | 17 | return $this->argument('name'); 18 | } 19 | 20 | /** 21 | * Get the value for the force option 22 | */ 23 | protected function optionForce(): bool|array|string|null 24 | { 25 | return $this->option('force'); 26 | } 27 | 28 | /** 29 | * Get the value for the plain option 30 | */ 31 | protected function optionPlain(): bool|array|string|null 32 | { 33 | return $this->option('plain'); 34 | } 35 | 36 | /** 37 | * Get the value for the stub option 38 | */ 39 | protected function optionStub(): bool|array|string|null 40 | { 41 | return $this->option('stub'); 42 | } 43 | 44 | /** 45 | * Get the value for the model option 46 | */ 47 | protected function optionModel(): bool|array|string|null 48 | { 49 | return $this->option('model'); 50 | } 51 | 52 | /** 53 | * Get the value for the schema option 54 | */ 55 | protected function optionSchema(): bool|array|string|null 56 | { 57 | return $this->option('schema'); 58 | } 59 | 60 | /** 61 | * Get the value for the name option 62 | */ 63 | protected function optionName(): bool|array|string|null 64 | { 65 | return $this->option('name'); 66 | } 67 | 68 | /** 69 | * Get the value for the name option 70 | */ 71 | protected function optionTest(): bool|array|string|null 72 | { 73 | return $this->option('test'); 74 | } 75 | 76 | /** 77 | * Get the value for the extra option 78 | */ 79 | protected function optionExtra(): bool|array|string|null 80 | { 81 | return $this->option($this->extraOption); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Traits/Settings.php: -------------------------------------------------------------------------------- 1 | option('type'); 20 | $options = config('generators.settings'); 21 | 22 | $found = false; 23 | // loop through the settings and find the type key 24 | foreach ($options as $key => $settings) { 25 | if ($type == $key) { 26 | $found = true; 27 | break; 28 | } 29 | } 30 | 31 | if ($found === false) { 32 | $this->error('Oops!, no settings key by the type name provided'); 33 | exit; 34 | } 35 | 36 | // set the default keys and values if they do not exist 37 | $defaults = config('generators.defaults'); 38 | foreach ($defaults as $key => $value) { 39 | if (!isset($settings[$key])) { 40 | $settings[$key] = $defaults[$key]; 41 | } 42 | } 43 | 44 | $this->settings = $settings; 45 | } 46 | 47 | /** 48 | * Return false or the value for given key from the settings 49 | * 50 | * @param $key 51 | * 52 | * @return bool 53 | */ 54 | public function settingsKey($key) 55 | { 56 | if (is_array($this->settings) == false || isset($this->settings[$key]) == false) { 57 | return false; 58 | } 59 | 60 | return $this->settings[$key]; 61 | } 62 | 63 | /** 64 | * Get the directory format setting's value 65 | */ 66 | protected function settingsDirectoryFormat() 67 | { 68 | return $this->settingsKey('directory_format') ? $this->settings['directory_format'] : false; 69 | } 70 | 71 | /** 72 | * Get the directory format setting's value 73 | */ 74 | protected function settingsDirectoryNamespace() 75 | { 76 | return $this->settingsKey('directory_namespace') ? $this->settings['directory_namespace'] : false; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | ['app', 'website', 'admin'], 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | The default keys and values for the settings of each type to be generated 17 | |-------------------------------------------------------------------------- 18 | */ 19 | 20 | 'defaults' => [ 21 | 'namespace' => '', 22 | 'path' => './app/', 23 | 'prefix' => '', 24 | 'postfix' => '', 25 | 'file_type' => '.php', 26 | 'dump_autoload' => false, 27 | 'directory_format' => '', 28 | 'directory_namespace' => false, 29 | ], 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Types of files that can be generated 34 | |-------------------------------------------------------------------------- 35 | */ 36 | 37 | 'settings' => [ 38 | 'view' => [ 39 | 'path' => './resources/views/', 40 | 'file_type' => '.blade.php', 41 | 'directory_format' => 'strtolower', 42 | 'directory_namespace' => true 43 | ], 44 | 'model' => ['namespace' => '\Models', 'path' => './app/Models/'], 45 | 'controller' => [ 46 | 'namespace' => '\Http\Controllers', 47 | 'path' => './app/Http/Controllers/', 48 | 'postfix' => 'Controller', 49 | 'directory_namespace' => true, 50 | 'dump_autoload' => false, 51 | 'repository_contract' => false, 52 | ], 53 | 'request' => [ 54 | 'namespace' => '\Http\Requests', 55 | 'path' => './app/Http/Requests/', 56 | 'postfix' => 'Request', 57 | 'directory_namespace' => true, 58 | ], 59 | 'seeder' => ['path' => './database/seeders/', 'postfix' => 'TableSeeder'], 60 | 'migration' => ['path' => './database/migrations/'], 61 | 'notification' => [ 62 | 'directory_namespace' => true, 63 | 'namespace' => '\Notifications', 64 | 'path' => './app/Notifications/' 65 | ], 66 | 'event' => [ 67 | 'directory_namespace' => true, 68 | 'namespace' => '\Events', 69 | 'path' => './app/Events/' 70 | ], 71 | 'listener' => [ 72 | 'directory_namespace' => true, 73 | 'namespace' => '\Listeners', 74 | 'path' => './app/Listeners/' 75 | ], 76 | 'trait' => [ 77 | 'directory_namespace' => true, 78 | ], 79 | 'job' => [ 80 | 'directory_namespace' => true, 81 | 'namespace' => '\Jobs', 82 | 'path' => './app/Jobs/' 83 | ], 84 | 'console' => [ 85 | 'directory_namespace' => true, 86 | 'namespace' => '\Console\Commands', 87 | 'path' => './app/Console/Commands/' 88 | ], 89 | 'exception' => [ 90 | 'directory_namespace' => true, 91 | 'namespace' => '\Exceptions', 92 | 'path' => './app/Exceptions/' 93 | ], 94 | 'middleware' => [ 95 | 'directory_namespace' => true, 96 | 'namespace' => '\Http\Middleware', 97 | 'path' => './app/Http/Middleware/' 98 | ], 99 | 'repository' => [ 100 | 'directory_namespace' => true, 101 | 'postfix' => 'Repository', 102 | 'namespace' => '\Repositories', 103 | 'path' => './app/Repositories/' 104 | ], 105 | 'contract' => [ 106 | 'directory_namespace' => true, 107 | 'namespace' => '\Contracts', 108 | 'postfix' => 'Repository', 109 | 'path' => './app/Contracts/', 110 | ], 111 | 'factory' => [ 112 | 'postfix' => 'Factory', 113 | 'path' => './database/factories/', 114 | ], 115 | 'test' => [ 116 | 'directory_namespace' => true, 117 | 'namespace' => '\Tests', 118 | 'postfix' => 'Test', 119 | 'path' => './tests/', 120 | ], 121 | 'livewire' => [ 122 | 'namespace' => '\Http\Livewire', 123 | 'path' => './app/Http/Livewire/', 124 | 'postfix' => '', 125 | 'directory_namespace' => true, 126 | ], 127 | 'livewire_view' => [ 128 | 'path' => './resources/views/livewire/', 129 | 'file_type' => '.blade.php', 130 | 'directory_format' => 'strtolower', 131 | 'directory_namespace' => true 132 | ], 133 | 'component' => [ 134 | 'namespace' => '\View\Components', 135 | 'path' => './app/View/Components/', 136 | 'postfix' => '', 137 | 'directory_namespace' => true, 138 | ], 139 | 'component_view' => [ 140 | 'path' => './resources/views/components/', 141 | 'file_type' => '.blade.php', 142 | 'directory_format' => 'strtolower', 143 | 'directory_namespace' => true 144 | ], 145 | ], 146 | 147 | /* 148 | |-------------------------------------------------------------------------- 149 | | Resource Views [stub_key | name of the file] 150 | |-------------------------------------------------------------------------- 151 | */ 152 | 153 | 'resource_views' => [ 154 | 'view_index' => 'index', 155 | //'view_create' => 'create', 156 | //'view_edit' => 'edit', 157 | 'view_show' => 'show', 158 | 'view_create_edit' => 'create_edit', 159 | ], 160 | 161 | /* 162 | |-------------------------------------------------------------------------- 163 | | Where the stubs for the generators are stored 164 | |-------------------------------------------------------------------------- 165 | */ 166 | 167 | 'stubs' => [ 168 | 'example' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/example.stub', 169 | 'model' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/model.stub', 170 | 'model_plain' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/model.plain.stub', 171 | 'migration' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/migration.stub', 172 | 'migration_plain' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/migration.plain.stub', 173 | 'controller' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/controller.stub', 174 | 'controller_plain' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/controller.plain.stub', 175 | 'controller_admin' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/controller_admin.stub', 176 | 'controller_repository' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/controller_repository.stub', 177 | 'request' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/request.stub', 178 | 'pivot' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/pivot.stub', 179 | 'seeder' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/seeder.stub', 180 | 'seeder_plain' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/seeder.plain.stub', 181 | 'view' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.stub', 182 | 'view_index' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.index.stub', 183 | 'view_indexb3' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.index.b3.stub', 184 | 'view_show' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.show.stub', 185 | 'view_showb3' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.show.b3.stub', 186 | //'view_create' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.create.stub', 187 | //'view_edit' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.edit.stub', 188 | 'view_create_edit' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.create_edit.stub', 189 | 'view_create_editb3' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/view.create_edit.b3.stub', 190 | 'schema_create' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/schema_create.stub', 191 | 'schema_change' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/schema_change.stub', 192 | 'notification' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/notification.stub', 193 | 'event' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/event.stub', 194 | 'listener' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/listener.stub', 195 | 'many_many_relationship' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/many_many_relationship.stub', 196 | 'trait' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/trait.stub', 197 | 'job' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/job.stub', 198 | 'console' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/console.stub', 199 | 'exception' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/exception.stub', 200 | 'middleware' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/middleware.stub', 201 | 'repository' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/repository.stub', 202 | 'repository_contract' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/repository.contract.stub', 203 | 'contract' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/contract.stub', 204 | 'factory' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/factory.stub', 205 | 'test' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/test.stub', 206 | 'livewire' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/livewire.stub', 207 | 'livewire_view' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/livewire.view.stub', 208 | 'component' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/component.stub', 209 | 'component_view' => base_path() . '/vendor/bpocallaghan/generators/resources/stubs/component.view.stub', 210 | ] 211 | ]; 212 | -------------------------------------------------------------------------------- /tests/ComponentCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:component foo'); 11 | $this->assertFileExists('app/View/Components/Foo.php'); 12 | $this->assertFileExists('resources/views/components/foo.blade.php'); 13 | 14 | $this->artisan('generate:component Bar'); 15 | $this->assertFileExists('app/View/Components/Bar.php'); 16 | $this->assertFileExists('resources/views/components/bar.blade.php'); 17 | 18 | $this->artisan('generate:component FooBar'); 19 | $this->assertFileExists('app/View/Components/FooBar.php'); 20 | $this->assertFileExists('resources/views/components/foo-bar.blade.php'); 21 | 22 | $this->artisan('generate:component Foo/Bar'); 23 | $this->assertFileExists('app/View/Components/Foo/Bar.php'); 24 | $this->assertFileExists('resources/views/components/foo/bar.blade.php'); 25 | 26 | $this->artisan('generate:component folder.foo'); 27 | $this->assertFileExists('app/View/Components/Folder/Foo.php'); 28 | $this->assertFileExists('resources/views/components/folder/foo.blade.php'); 29 | 30 | $this->artisan('generate:component folder.foo-bar'); 31 | $this->assertFileExists('app/View/Components/Folder/FooBar.php'); 32 | $this->assertFileExists('resources/views/components/folder/foo-bar.blade.php'); 33 | } 34 | 35 | /** @test */ 36 | public function generate_component_test_option() 37 | { 38 | $this->artisan('generate:component Foo --test'); 39 | $this->assertFileExists('app/View/Components/Foo.php'); 40 | $this->assertFileExists('resources/views/components/foo.blade.php'); 41 | $this->assertFileExists('tests/Unit/View/Components/FooTest.php'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/ConsoleCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:console SendEmails'); 11 | $this->assertFileExists('app/Console/Commands/SendEmails.php'); 12 | } 13 | 14 | /** @test */ 15 | public function generate_console_with_option_test() 16 | { 17 | $this->artisan('generate:job NotifyApi --test'); 18 | $this->assertFileExists('app/Jobs/NotifyApi.php'); 19 | $this->assertFileExists('tests/Unit/Jobs/NotifyApiTest.php'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/ContractCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:contract Cache'); 11 | $this->assertFileExists('app/Contracts/CacheRepository.php'); 12 | 13 | $this->artisan('generate:contract PostsRepository'); 14 | $this->assertFileExists('app/Contracts/PostsRepository.php'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/ControllerCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:controller test'); 11 | $this->assertFileExists('app/Http/Controllers/TestController.php'); 12 | } 13 | 14 | /** @test */ 15 | public function uppercase_file_name() 16 | { 17 | $this->artisan('generate:controller foo.bar'); 18 | $this->assertFileExists('app/Http/Controllers/Foo/BarController.php'); 19 | 20 | $this->artisan('generate:controller fooBar'); 21 | $this->assertFileExists('app/Http/Controllers/FooBarController.php'); 22 | } 23 | 24 | /** @test */ 25 | public function option_plain_stub() 26 | { 27 | $this->artisan('generate:controller plain --plain'); 28 | $this->assertFileExists('app/Http/Controllers/PlainController.php'); 29 | } 30 | 31 | /** @test */ 32 | public function do_not_include_controller_suffix_if_already_in_name() 33 | { 34 | $this->artisan('generate:controller SuffixController'); 35 | $this->assertFileExists('app/Http/Controllers/SuffixController.php'); 36 | } 37 | 38 | /** @test */ 39 | public function generate_controller_with_option_test() 40 | { 41 | $this->artisan('generate:controller foo --test'); 42 | $this->assertFileExists('app/Http/Controllers/FooController.php'); 43 | $this->assertFileExists('tests/Feature/Controllers/FooControllerTest.php'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/EventCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:event InvoiceWasPaid'); 11 | $this->assertFileExists('app/Events/InvoiceWasPaid.php'); 12 | 13 | $this->artisan('generate:listener NotifyUserAboutPayment --event=InvoiceWasPaid'); 14 | $this->assertFileExists('app/Listeners/NotifyUserAboutPayment.php'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/ExceptionCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:exception UserIsNotLoggedIn'); 11 | $this->assertFileExists('app/Exceptions/UserIsNotLoggedIn.php'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/FactoryCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:factory Post'); 11 | $this->assertFileExists('database/factories/PostFactory.php'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/FileCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:file test'); 11 | 12 | $this->assertFileExists('resources/views/test.blade.php'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/JobCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:job SendReminderEmail'); 11 | $this->assertFileExists('app/Jobs/SendReminderEmail.php'); 12 | } 13 | 14 | /** @test */ 15 | public function generate_job_with_option_test() 16 | { 17 | $this->artisan('generate:job ProductPaid --test'); 18 | $this->assertFileExists('app/Jobs/ProductPaid.php'); 19 | $this->assertFileExists('tests/Unit/Jobs/ProductPaidTest.php'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/LivewireCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:livewire foo'); 11 | $this->assertFileExists('app/Http/Livewire/Foo.php'); 12 | $this->assertFileExists('resources/views/livewire/foo.blade.php'); 13 | 14 | $this->artisan('generate:livewire Bar'); 15 | $this->assertFileExists('app/Http/Livewire/Bar.php'); 16 | $this->assertFileExists('resources/views/livewire/bar.blade.php'); 17 | 18 | $this->artisan('generate:livewire FooBar'); 19 | $this->assertFileExists('app/Http/Livewire/FooBar.php'); 20 | $this->assertFileExists('resources/views/livewire/foo-bar.blade.php'); 21 | 22 | $this->artisan('generate:livewire Foo/Bar'); 23 | $this->assertFileExists('app/Http/Livewire/Foo/Bar.php'); 24 | $this->assertFileExists('resources/views/livewire/foo/bar.blade.php'); 25 | 26 | $this->artisan('generate:livewire folder.foo'); 27 | $this->assertFileExists('app/Http/Livewire/Folder/Foo.php'); 28 | $this->assertFileExists('resources/views/livewire/folder/foo.blade.php'); 29 | 30 | $this->artisan('generate:livewire folder.foo-bar'); 31 | $this->assertFileExists('app/Http/Livewire/Folder/FooBar.php'); 32 | $this->assertFileExists('resources/views/livewire/folder/foo-bar.blade.php'); 33 | } 34 | 35 | /** @test */ 36 | public function generate_livewire_test_option() 37 | { 38 | $this->artisan('generate:livewire Foo --test'); 39 | $this->assertFileExists('app/Http/Livewire/Foo.php'); 40 | $this->assertFileExists('resources/views/livewire/foo.blade.php'); 41 | $this->assertFileExists('tests/Feature/Livewire/FooTest.php'); 42 | } 43 | 44 | /** @test */ 45 | public function generate_livewire_request_option() 46 | { 47 | $this->artisan('generate:livewire Foo/Bar/Baz --request'); 48 | $this->assertFileExists('app/Http/Livewire/Foo/Bar/Baz.php'); 49 | $this->assertFileExists('resources/views/livewire/foo/bar/baz.blade.php'); 50 | $this->assertFileExists('app/Http/Requests/Foo/Bar/BazRequest.php'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/MiddlewareCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:middleware AuthenticateAdmin'); 11 | $this->assertFileExists('app/Http/Middleware/AuthenticateAdmin.php'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/MigrationCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:migration create_users_table'); 11 | $this->assertFileExists('app/Models/User.php'); 12 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_users_table.php'); 13 | 14 | $this->artisan('generate:migration create_user_comments_table'); 15 | $this->assertFileExists('app/Models/UserComment.php'); 16 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_user_comments_table.php'); 17 | } 18 | 19 | /** @test */ 20 | public function generate_migration_pivot() 21 | { 22 | $this->artisan('generate:migration create_tags_table'); 23 | $this->artisan('generate:migration create_posts_table'); 24 | $this->artisan('generate:migration:pivot tags posts')->expectsQuestion("Add Many To Many Relationship in 'Tag' and 'Post' Models? [yes|no]", 'yes')->assertExitCode(0); 25 | 26 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_post_tag_pivot_table.php'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/ModelCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:model test'); 11 | $this->assertFileExists('app/Models/Test.php'); 12 | 13 | $this->artisan('generate:model foo'); 14 | $this->assertFileExists('app/Models/Foo.php'); 15 | 16 | $this->artisan('generate:model foo.bar'); 17 | $this->assertFileExists('app/Models/Bar.php'); 18 | 19 | $this->artisan('generate:model plain --plain'); 20 | $this->assertFileExists('app/Models/Plain.php'); 21 | 22 | $this->artisan('generate:model foo --force'); 23 | $this->assertFileExists('app/Models/Foo.php'); 24 | } 25 | 26 | /** @test */ 27 | public function generate_model_with_migration() 28 | { 29 | $this->artisan('generate:model foo --migration'); 30 | $this->assertFileExists('app/Models/Foo.php'); 31 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_foos_table.php'); 32 | 33 | $this->artisan('generate:model UserComment --migration'); 34 | $this->assertFileExists('app/Models/UserComment.php'); 35 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_user_comments_table.php'); 36 | } 37 | 38 | /** @test */ 39 | public function generate_model_with_option_factory() 40 | { 41 | $this->artisan('generate:model Comment --factory'); 42 | $this->assertFileExists('app/Models/Comment.php'); 43 | $this->assertFileExists('database/factories/CommentFactory.php'); 44 | } 45 | 46 | /** @test */ 47 | public function generate_model_with_option_test() 48 | { 49 | $this->artisan('generate:model Post --test'); 50 | $this->assertFileExists('app/Models/Post.php'); 51 | $this->assertFileExists('tests/Unit/Models/PostTest.php'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/NotificationCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:notification ContractUsSubmitted'); 11 | $this->assertFileExists('app/Notifications/ContractUsSubmitted.php'); 12 | 13 | $this->artisan('generate:notification Admin/UserRegistered'); 14 | $this->assertFileExists('app/Notifications/Admin/UserRegistered.php'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/RepositoryCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:repository Post'); 11 | $this->assertFileExists('app/Repositories/PostRepository.php'); 12 | 13 | $this->artisan('generate:repository TagsRepository'); 14 | $this->assertFileExists('app/Repositories/TagsRepository.php'); 15 | } 16 | 17 | /** @test */ 18 | public function generate_repository_with_option_test() 19 | { 20 | $this->artisan('generate:repository Foo --test'); 21 | $this->assertFileExists('app/Repositories/FooRepository.php'); 22 | $this->assertFileExists('tests/Unit/Repositories/FooRepositoryTest.php'); 23 | } 24 | 25 | /** @test */ 26 | public function generate_repository_with_contract_stub() 27 | { 28 | $this->artisan('generate:repository BookingRepository --contract'); 29 | $this->assertFileExists('app/Repositories/BookingRepository.php'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/RequestCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:request PostStore'); 11 | $this->assertFileExists('app/Http/Requests/PostStoreRequest.php'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/ResourceCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:resource post') 11 | ->expectsQuestion('Create a Post model?', true) 12 | ->expectsQuestion('Create crud views for the post resource?', true) 13 | ->expectsQuestion('Create a controller (PostsController) for the post resource?', true) 14 | ->expectsQuestion('Create a migration (create_posts_table) for the post resource?', true) 15 | ->expectsQuestion('Create a seeder (PostsTableSeeder) for the post resource?', true) 16 | ->expectsQuestion('Create a test (PostTest) for the post resource?', true) 17 | ->expectsQuestion('Create a factory (PostFactory) for the post resource?', true) 18 | ->expectsQuestion('Migrate the database?', false) 19 | ->expectsQuestion('Run \'composer dump-autoload\'?', false) 20 | ->assertExitCode(0); 21 | 22 | $this->assertFileExists('app/Models/Post.php'); 23 | $this->assertFileExists('resources/views/post/create_edit.blade.php'); 24 | $this->assertFileExists('resources/views/post/index.blade.php'); 25 | $this->assertFileExists('resources/views/post/show.blade.php'); 26 | $this->assertFileExists('app/Http/Controllers/PostsController.php'); 27 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_posts_table.php'); 28 | $this->assertFileExists('database/factories/PostFactory.php'); 29 | $this->assertFileExists('database/seeders/PostsTableSeeder.php'); 30 | // $this->assertFileExists('tests/Feature/PostTest.php'); 31 | $this->assertFileExists('tests/Unit/PostTest.php'); 32 | } 33 | 34 | /** @test */ 35 | public function generate_resource_with_admin_controller_stub() 36 | { 37 | $this->artisan('generate:resource articles --controller=admin') 38 | ->expectsQuestion('Create a Article model?', true) 39 | ->expectsQuestion('Create crud views for the article resource?', true) 40 | ->expectsQuestion('Create a controller (ArticlesController) for the article resource?', true) 41 | ->expectsQuestion('Create a migration (create_articles_table) for the article resource?', true) 42 | ->expectsQuestion('Create a seeder (ArticlesTableSeeder) for the article resource?', true) 43 | ->expectsQuestion('Create a test (ArticleTest) for the article resource?', true) 44 | ->expectsQuestion('Create a factory (ArticleFactory) for the article resource?', true) 45 | ->expectsQuestion('Migrate the database?', false) 46 | ->expectsQuestion('Run \'composer dump-autoload\'?', false) 47 | ->assertExitCode(0); 48 | 49 | $this->assertFileExists('app/Models/Article.php'); 50 | $this->assertFileExists('resources/views/articles/create_edit.blade.php'); 51 | $this->assertFileExists('resources/views/articles/index.blade.php'); 52 | $this->assertFileExists('resources/views/articles/show.blade.php'); 53 | $this->assertFileExists('app/Http/Controllers/ArticlesController.php'); 54 | $this->assertFileExists('database/migrations/'. date('Y_m_d_His') .'_create_articles_table.php'); 55 | $this->assertFileExists('database/factories/ArticleFactory.php'); 56 | $this->assertFileExists('database/seeders/ArticlesTableSeeder.php'); 57 | // $this->assertFileExists('tests/Feature/ArticlesTest.php'); 58 | $this->assertFileExists('tests/Unit/ArticleTest.php'); 59 | } 60 | 61 | /** @test */ 62 | public function generate_resource_with_bootstrap_4_stubs() 63 | { 64 | $this->artisan('generate:resource articles --view=b3') 65 | ->expectsQuestion('Create a Article model?', false) 66 | ->expectsQuestion('Create crud views for the article resource?', true) 67 | ->expectsQuestion('Create a controller (ArticlesController) for the article resource?', false) 68 | ->expectsQuestion('Create a migration (create_articles_table) for the article resource?', false) 69 | ->expectsQuestion('Create a seeder (ArticlesTableSeeder) for the article resource?', false) 70 | ->expectsQuestion('Create a test (ArticleTest) for the article resource?', false) 71 | ->expectsQuestion('Create a factory (ArticleFactory) for the article resource?', false) 72 | ->expectsQuestion('Migrate the database?', false) 73 | ->expectsQuestion('Run \'composer dump-autoload\'?', false) 74 | ->assertExitCode(0); 75 | 76 | $this->assertFileExists('resources/views/articles/create_edit.blade.php'); 77 | $this->assertFileExists('resources/views/articles/index.blade.php'); 78 | $this->assertFileExists('resources/views/articles/show.blade.php'); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/SeederCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:seeder post'); 11 | $this->assertFileExists('database/seeders/PostsTableSeeder.php'); 12 | 13 | $this->artisan('generate:seeder UserTableSeeder'); 14 | $this->assertFileExists('database/seeders/UsersTableSeeder.php'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | cleanOutputDirectory(); 16 | } 17 | 18 | private function cleanOutputDirectory(): void 19 | { 20 | if (File::isDirectory('output')) { 21 | File::deleteDirectories('output'); 22 | } 23 | 24 | //if (File::isDirectory('resources')) { 25 | // File::deleteDirectories('resources'); 26 | //} 27 | 28 | if (File::isDirectory('app')) { 29 | File::deleteDirectories('app'); 30 | } 31 | 32 | if (File::isDirectory('database')) { 33 | File::deleteDirectories('database'); 34 | } 35 | } 36 | 37 | /** 38 | * Load package service provider. 39 | * 40 | * @param \Illuminate\Foundation\Application $app 41 | * @return array 42 | */ 43 | protected function getPackageProviders($app): array 44 | { 45 | return [ 46 | GeneratorsServiceProvider::class 47 | ]; 48 | } 49 | 50 | /** 51 | * Resolve application core configuration implementation. 52 | * 53 | * @param \Illuminate\Foundation\Application $app 54 | * 55 | * @return void 56 | */ 57 | protected function resolveApplicationConfiguration($app): void 58 | { 59 | parent::resolveApplicationConfiguration($app); 60 | 61 | $path = __DIR__ . '/../resources/stubs/'; 62 | 63 | $app['config']->set('generators.stubs.example', "{$path}example.stub"); 64 | $app['config']->set('generators.stubs.model', "{$path}model.stub"); 65 | $app['config']->set('generators.stubs.model_plain', "{$path}model.plain.stub"); 66 | $app['config']->set('generators.stubs.migration', "{$path}migration.stub"); 67 | $app['config']->set('generators.stubs.migration_plain', "{$path}migration.plain.stub"); 68 | $app['config']->set('generators.stubs.controller', "{$path}controller.stub"); 69 | $app['config']->set('generators.stubs.controller_plain', "{$path}controller.plain.stub"); 70 | $app['config']->set('generators.stubs.controller_admin', "{$path}controller_admin.stub"); 71 | $app['config']->set('generators.stubs.controller_repository', "{$path}controller_repository.stub"); 72 | $app['config']->set('generators.stubs.request', "{$path}request.stub"); 73 | $app['config']->set('generators.stubs.pivot', "{$path}pivot.stub"); 74 | $app['config']->set('generators.stubs.seeder', "{$path}seeder.stub"); 75 | $app['config']->set('generators.stubs.seeder_plain', "{$path}seeder.plain.stub"); 76 | $app['config']->set('generators.stubs.view', "{$path}view.stub"); 77 | $app['config']->set('generators.stubs.view_index', "{$path}view.index.stub"); 78 | $app['config']->set('generators.stubs.view_indexb4', "{$path}view.index.b4.stub"); 79 | $app['config']->set('generators.stubs.view_show', "{$path}view.show.stub"); 80 | $app['config']->set('generators.stubs.view_showb4', "{$path}view.show.b4.stub"); 81 | $app['config']->set('generators.stubs.view_create_edit', "{$path}view.create_edit.stub"); 82 | $app['config']->set('generators.stubs.view_create_editb4', "{$path}view.create_edit.b4.stub"); 83 | $app['config']->set('generators.stubs.schema_create', "{$path}schema_create.stub"); 84 | $app['config']->set('generators.stubs.schema_change', "{$path}schema_change.stub"); 85 | $app['config']->set('generators.stubs.notification', "{$path}notification.stub"); 86 | $app['config']->set('generators.stubs.event', "{$path}event.stub"); 87 | $app['config']->set('generators.stubs.listener', "{$path}listener.stub"); 88 | $app['config']->set('generators.stubs.many_many_relationship', "{$path}many_many_relationship.stub"); 89 | $app['config']->set('generators.stubs.trait', "{$path}trait.stub"); 90 | $app['config']->set('generators.stubs.job', "{$path}job.stub"); 91 | $app['config']->set('generators.stubs.console', "{$path}console.stub"); 92 | $app['config']->set('generators.stubs.middleware', "{$path}middleware.stub"); 93 | $app['config']->set('generators.stubs.repository', "{$path}repository.stub"); 94 | $app['config']->set('generators.stubs.repository_contract', "{$path}repository.contract.stub"); 95 | $app['config']->set('generators.stubs.contract', "{$path}contract.stub"); 96 | $app['config']->set('generators.stubs.factory', "{$path}factory.stub"); 97 | $app['config']->set('generators.stubs.exception', "{$path}exception.stub"); 98 | $app['config']->set('generators.stubs.test', "{$path}test.stub"); 99 | $app['config']->set('generators.stubs.livewire', "{$path}livewire.stub"); 100 | $app['config']->set('generators.stubs.livewire_view', "{$path}livewire.view.stub"); 101 | $app['config']->set('generators.stubs.component', "{$path}component.stub"); 102 | $app['config']->set('generators.stubs.component_view', "{$path}component.view.stub"); 103 | 104 | // $path = '../tests/output/'; 105 | // dd($app['config']->get('generators')); 106 | //$app['config']->set('generators.settings.view.path', "{$path}resources/views/"); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /tests/TestCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:test Controllers/UsersController'); 11 | $this->assertFileExists('tests/Feature/Controllers/UsersControllerTest.php'); 12 | 13 | $this->artisan('generate:test Models/Post --unit'); 14 | $this->assertFileExists('tests/Unit/Models/PostTest.php'); 15 | 16 | $this->artisan('generate:test Traits/InvoiceTest --unit'); 17 | $this->assertFileExists('tests/Unit/Traits/InvoiceTest.php'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/TraitCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:trait Traits/UserHelper'); 11 | $this->assertFileExists('app/Traits/UserHelper.php'); 12 | 13 | $this->artisan('generate:trait Http/Controllers/Traits/PhotoHelper'); 14 | $this->assertFileExists('app/Http/Controllers/Traits/PhotoHelper.php'); 15 | } 16 | 17 | /** @test */ 18 | public function generate_trait_with_option_test() 19 | { 20 | $this->artisan('generate:trait Traits/RoleHelper --test'); 21 | $this->assertFileExists('app/Traits/RoleHelper.php'); 22 | $this->assertFileExists('tests/Unit/Traits/RoleHelperTest.php'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/ViewCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('generate:view view'); 11 | $this->assertFileExists('resources/views/view.blade.php'); 12 | 13 | $this->artisan('generate:view foo.bar'); 14 | $this->assertFileExists('resources/views/foo/bar.blade.php'); 15 | 16 | $this->artisan('generate:view foo --stub=view_show'); 17 | $this->assertFileExists('resources/views/foo.blade.php'); 18 | 19 | $this->artisan('generate:view foo --name=foo_bar'); 20 | $this->assertFileExists('resources/views/foo/foo_bar.blade.php'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpocallaghan/generators/b627bf48420f5ed9e2375defdb5421c34b121029/todo.md --------------------------------------------------------------------------------